基于TCP/UDP的Socket编程

这篇具有很好参考价值的文章主要介绍了基于TCP/UDP的Socket编程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

---- socket概述:

socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。

socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

---- 接口简介:

socket():创建socket

bind():绑定socket到本地地址和端口,通常由服务端调用

listen():TCP专用,开启监听模式

accept():TCP专用,服务器等待客户端连接,一般是阻塞态

connect():TCP专用,客户端主动连接服务器

send():TCP专用,发送数据

recv():TCP专用,接收数据

sendto():UDP专用,发送数据到指定的IP地址和端口

recvfrom():UDP专用,接收数据,返回数据远端的IP地址和端口

closesocket():关闭socket

---- 流程如下:

基于TCP/UDP的Socket编程

接口详解,常用的系统调用如下:

>> socket() : creating  a socket 

A socket is an abstraction of a communication endpoint. Just as they would use file descriptors to access files, applications use socket descriptors to access sockets. To create a socket, we call the socket() function.

原型:int socket(int domain, int type, int protocol);

返回值: returns file (socket) descriptor if OK, -1 on error.

domain:AF_INET, AF_INET6, AF_UNIX, AF_UNSPEC (address format)

type:SOCK_DGRAM, SOCK_RAW, SOCK_STREAM, SOCK_SEQPACKET

protocol:IPPROTO_IP,  IPPROTO_IPV6,  IPPROTO_TCP, IPPROTO_UDP

The protocol argument is usually zero, to select the default protocol for the given domain and socket type. The default protocol for a SOCK_STREAM socket in the AF_INET communication domain is TCP(Transmission Control Protocol). The default protocol for a SOCK_DGRAM socket in the AF_INET communication domain is UDP(User Datagram Protocol).

NOTE: UDP -- 数据报(datagram),无连接的,no logical connection exist between peers for them to communicate. A datagram is a self-contained(独立的) message. 类似于(analogous)发邮件,你可以发送多封邮件,但是不能保证邮件是否到达和邮件到达的顺序。每一封邮件都包含了接收者的地址。

TCP -- 字节流 A byte stream(SOCK_STREAM), in contrast, 在传输数据之前,需要建立连接,面向连接的通信类似于打电话。点到点的连接里包含了source and destination。

Communication on a socket is bidirectional. We can disable I/O on a socket with the shutdown function.

>> shutdown()   

原型:int shutdown(int sockfd, int how);

返回值: returns 0 if OK, -1 on error.

The shutdown() system call closes one or both channels of the socket sockfd, depending on the value of how, which is specified as one of the following:

how:  SHUT_RD, then reading from the socket is disabled.  SHUT_WR, then we can't use the socket for transmitting data. We can use SHUT_RDWR to disable both data transmission and reception.

shutdown() differs from close() in another important respect: it closes the socket channels regardless of whether there are other file descriptors referring to the socket. For example, sockfd refers to a connected stream socket. If we make the following calls, then the connection remains open, and we can still perform I/O on the connection via the file descriptor fd2:

1.    fd = dup(sockfd);

2.    close(sockfd);

However, if we make the following sequence of calls, then both channels of the connection are closed, and I/O can no longer be performed via fd2:

1.    fd2 = dup(sockfd);

2.    shutdown(sockfd,SHUT_RDWR);

Note that shutdown() doesn't close the file descriptor, even if how is specified as SHUT_RDWR. To close the file descriptor, we must additionally call close().

>> bind() : binding a socket to an address    

The bind() system call binds a socket to an address.

原型:int bind(int sockfd, const struct sockaddr * addr, socklen_t addrlen);

返回值:returns 0 on success, or -1 on error.

The sockfd argument is a file descriptor obtained from a previous call to socket(). The addr argument is a pointer to a structure specifying the address to which this socket is to be bound. The type of structure passed in this argument depends on the socket domain. The addrlen argument specifies the size of the address structure.

Typically, we bind a server's socket to a well-known address - that is, a fixed address that is known in advance to client applications that need to communicate with that server.

>> listen() : listening for incoming connections    

原型:int listen(int sockfd, int backlog); // returns 0 on success, or -1 on error.

The listen() system call marks the stream socket referred to by the file descriptor sockfd as passive. The socket will subsequently be used to accept connections from other(active) sockets.

The client may call connect() before the server calls accept(). This could happen, for example, because the server is busy handling some other clients. This results in a pending connection, as illustrated in Figure 56-2.

基于TCP/UDP的Socket编程

The kernel must record some information about each pending connection request so that a subsequent accept() can be processed. The backlog argument allows us to limit the number of such pending connections. Further connection requests block until a pending connection is accepted(via accept()), and thus removed from the queue of pending connections.

>> accept() : accepting a connection   

The accept() system call accepts an incoming connection on the listening stream socket referred to by the file descriptor sockfd. If there are no pending connections when accept() is called, the call blocks until a connection request arrives when the sockfd in block mode. If sockfd is in nonblocking mode, accept() will return -1 and set errno to either EAGAIN or EWOULDBLOCK.

原型:int accept(int sockfd, struct sockaddr * restrict addr, socklen_t * restrict len);

返回值:return file(socket) descriptor if OK, -1 on error.

本函数从s的等待连接队列中抽取第一个连接,创建一个与s同类的新的套接口并返回句柄。如果队列中无等待连接,且套接口为阻塞方式,则accept()阻塞调用进程直至新的连接出现。如果套接口为非阻塞方式且队列中无等待连接,则accept()返回一错误代码WSAEWOULDBLOCK。已接受连接的套接口不能用于接受新的连接,原监听套接口仍保持开放。

The key point to understand about accept() is that it creates a new socket, and this new socket that is connected to the peer socket that performed the connect(). This new socket descriptor has the same socket type and address family as the  original socket(sockfd). A file descriptor for the connected socket is returned as the function result of the accept() call. The listening socket(sockfd) remains open, and can be used to accept further connections. A typical server application creates one listening socket, binds it to a well-known address, and then handles all client requests by accepting connections via that socket.

The remaining(剩余的) arguments to accept() return the address of the peer socket.(客户端)

If we don't care about the client's identity, we can set the addr and len parameters to NULL. Otherwise, before calling accept, we need to set the addr (指向一个buffer) parameter to a buffer large enough to hold the address and set the integer pointed to by len to the size of the buffer in bytes. On return, accept will fill in the client's address in the buffer and update the integer pointed to by len to reflect the size of the address.

>> connect() : connecting to a peer socket  

原型:int connect(int sockfd, const struct sockaddr * addr, socklen_t addrlen);

返回值: returns 0 on success, or -1 on error.

The connect() system call connects the active socket referred to by the file descriptor sockfd to the listening socket whose address is specified by addr and addrlen.

>> send() : TCP类型的数据发送 

原型:int send(int sockfd, const void * msg, int len, int flags);

每个TCP套接口都有一个发送缓冲区,它的大小可以用SO_SNDBUF这个选项来改变。调用send函数的过程实际是内核将用户数据(msg)拷贝至TCP套接口的发送缓冲区的过程。若len大于发送缓冲区的大小,则返回-1. 否则,查看缓冲区剩余空间是否容纳得下要发送的len长度,若不够,则拷贝一部分,并返回拷贝长度(指的是非阻塞send,若为阻塞send,则一定等待所有数据拷贝至缓冲区才返回,因此阻塞send返回值必定与len相等)。若缓冲区满,则等待发送,有剩余空间后拷贝至缓冲区,若在拷贝过程中出现错误,则返回-1.关于错误的原因,查看errno的值。

注意:send成功返回并不代表对方已接收到数据,如果后续的协议传输过程中出现网络错误,下一个send便会返回-1发送错误。TCP给对方的数据必须在对方给予确认时,方可删除发送缓冲区的数据。否则,会一直缓存到缓冲区直至发送成功。

参数解释:

sockfd -- 发送端套接字描述符 (非监听描述符)

msg -- 待发送数据的缓冲区 (将其内容的len长度拷贝到socket的发送缓冲区)

len -- 待发送数据的字节长度。

flags -- 一般情况下置为0.

基于TCP/UDP的Socket编程

>> recv() : TCP类型的数据接收 

原型:int recv(int sockfd, void *buf, int len, unsigned int flags);

recv()从接收缓冲区拷贝数据。成功时,返回拷贝的字节数,失败时,返回-1。阻塞模式下,recv()将会阻塞直到缓冲区中至少有一个字节才返回,没有数据时处于休眠状态。若非阻塞,则立即返回,有数据则返回拷贝的数据大小,否则返回错误-1.

参数解释:

sockfd -- 接收端套接字描述符(非监听描述符)

buf -- 接收数据的基地址(将socket的接收缓冲区中的内容拷贝至buf中)

len -- 接收到数据的字节数

flags -- 一般情况下置为0.

>> sendto() : UDP类型的数据发送 

原型:int sendto(int sockfd, const void * msg, int len, unsigned int flags, const struct sockaddr * dst_addr, int addrlen);

用于非可靠连接(UDP)的数据发送,因为UDP方式未建立连接socket,因此需要指定目的socket的address。

可使用同一个UDP套接口描述符sockfd和不同的目的地址通信。而TCP要预先建立连接,每个连接都会产生不同的套接口描述符,体现在:客户端要使用不同的fd进行connect,服务端每次accept产生不同的fd。

UDP没有真正的发送缓冲区,因为是不可靠连接,不必保存应用进程的数据拷贝,应用进程的数据在沿协议栈向下传递时,以某种形式拷贝到内核缓冲区,当数据链路层把数据传出后就把内核缓冲区中数据拷贝删除。因此它不需要一个发送缓冲区。

For sendto(), the dest_addr and addrlen arguments specify the socket to which the datagram is to be sent. These arguments are employed in the same manner as the corresponding arguments to connect(). The dest_addr argument is an address structure suitable for this communication domain. It is initialized with the address of the destination socket. The addrlen argument specifies the size of addr.

>> recvfrom() : UDP类型的数据接收 

原型:int recvfrom(int sockfd, void * buf, size_t len, int flags, struct sockaddr * src_addr, int * addrlen);

参数解释:

sockfd -- 接收端套接字描述;

buf -- 用于接收数据的应用缓冲区地址;

len -- 指明缓冲区大小;

flags -- 通常为0;

src_addr -- 数据来源端的地址(IP address,Port number).

fromlen -- 作为输入时,fromlen常常设置为sizeof(struct sockaddr).

For recvfrom(), the src_addr and addrlen arguments return the address of the remote socket used to send the datagram. (These arguments are analogous to the addr and addrlen arguments of accept(), which return the address of a connecting peer socket.) Prior to the call(在调用之前), addrlen should be initialized to the size of the structure pointed to by src_addr(结构的大小); upon return(在返回时), it contains the number of bytes actually written to this structure.

对嵌入式物联网感兴趣的小伙伴,可以多了解一下相关信息。(看过来)文章来源地址https://www.toymoban.com/news/detail-498732.html

到了这里,关于基于TCP/UDP的Socket编程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python使用 Twisted 实现 TCP/UDP Socket 编程

    更多文章: 技数未来 环境准备: - 安装Python:确保你已经安装了Python解释器。 - 安装Twisted:可以通过pip命令来安装Twisted库,运行`pip install twisted`即可。 依赖的类库: - twisted.internet.protocol:包含了实现TCP/UDP Socket编程所需的协议类。 - twisted.internet.reactor:用于处理事件循环

    2024年02月16日
    浏览(48)
  • Socket套接字编程(实现TCP和UDP的通信)

      🎉🎉🎉点进来你就是我的人了 博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 人生格言: 当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔 🦾🦾🦾 目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个🐒嘿嘿 谢谢

    2024年02月03日
    浏览(91)
  • socket的基本使用,基于TCP/UDP

    OSI参考模型 Open System Interconnect 开放式系统 每层网络的由来 物理层:010101比特流,设备之间原始数据的传输,数模转换(发送端)和模数转换(接收端) -》传输过程可能出现错码和误码? 数据链路层:将原始比特流转换成逻辑传输符号,提供纠错编码,格式变为帧 -》出现

    2024年02月03日
    浏览(39)
  • C/C++ Linux Socket网络编程 TCP 与 UDP

    之前已经学习了QT的socket编程 和 C/C++在window环境的socket编程,现在再来学习一波C/C++在Linux环境下的socket编程,为以后学习C++ Linux 服务器开发做准备。 目录 一、Socket简介 二、Socket编程基础 1. 网络字节序 2. sockaddr数据结构 3. IP地址转换函数 三、TCP编程函数 1. socket函数 2. bi

    2024年02月02日
    浏览(61)
  • Java网络编程基础:TCP Socket套接字编程 IntAddress UDP等...

    目录 一,网络基础 1.IP地址 2.端口 3.TCP/UDP协议 4.网络编程开发模式  二,基于套接字的Java网络编程 1.Socket  2.InetAddress 三.基于TCP的Socket网络编程 1.单服务器端与单Socket客户端一次通讯 2.单服务器端接收多次通讯  3.TCP网络通讯补充 四,基于UDP的网络编程 1. DatagramSocket:收发

    2024年04月29日
    浏览(45)
  • 基于python socket实现TCP/UDP通信

    两个应用程序如果需要进行通讯最基本的一个前提就是能够唯一的标示一个进程,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。能够唯一标示网络中的进程后

    2024年02月16日
    浏览(51)
  • 【socket】从计算机网络基础到socket编程——Windows && Linux C语言 + Python实现(TCP+UDP)

    简单讲一下基础知识,便于后面代码的理解,建议大概浏览一下这一小节内容。这里讲的只是冰山一角,建议大家学习计算机网络相关知识,推荐几本书: 《计算机网络》(谢希仁) 《计算机网络 自顶向下方法》 《计算机网络技术》 《计算机网络基础及应用》 《Linux C从入

    2024年02月08日
    浏览(60)
  • Java网络编程(二)Socket 套接字(TCP和UDP),以及TCP的回显

    我们软件工作者,着重编写的是应用层的代码,但是发送这个数据,我们就需要将应用层传输到传输层,也就意味着我们需要调用应用层的API,统称为 Socket API。 套接字的分类: 流套接字:使用传输层TCP协议 特点: 有连接:使用 TCP 通信的双方,需要时刻保存对方的相关消

    2024年02月09日
    浏览(53)
  • 网络:从socket编程的角度说明UDP和TCP的关系,http和tcp的区别

             尝试从编程的角度解释各种网络协议。         从Python的socket编程角度出发,UDP( User Datagram Protocol )和TCP( Transmission Control Protocol )是两种不同的传输协议。 TCP是一种面向连接的协议,提供可靠的、有序的、双向的数据传输。在TCP中,客户端和服务器之间

    2024年02月14日
    浏览(38)
  • Socket编程详解:从基本概念到实例应用(TCP|UDP C语言实例详解)

    简介: Socket编程是网络编程中至关重要的一部分,它提供了一种在不同主机之间进行数据通信的方式。本篇博客将详细介绍Socket编程的基本概念、原理和实例应用,帮助读者深入理解和掌握这一重要技术。 正文: 一、Socket编程概述 Socket是一种通信机制,通过它可以在不同主

    2024年02月14日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包