linux下socket编程

1、UDP网络编程主要流程

UDP协议的编程框架,客户端和服务器端的区别在于,服务器端必须使用bind()函数绑定监听本地UDP端口,而客户端可以直接发送到服务器地址的一个端口地址,无需绑定。框图如图1.3所示。

UDP协议的服务器端进程

服务器进程主要分为以下六个部分,即建立套接字、设置套接字地址参数、绑定端口、接收数据、发送数据、关闭套接字等。

(1)建立套接字文件描述符,使用函数socket()生成套接字文件描述符。

(2)设置服务器地址和监听端口,初始化要绑定的网络地址结构。

(3)绑定监听端口,使用bind()函数将socket文件描述符与地址类型变量绑定。

(4)接收客户端的数据,使用recvfrom()函数接收客户端的网络数据。

(5)向客户端发送数据,使用sendto()函数向服务器主机发送数据。

(6)关闭套接字,使用close()函数释放资源。UDP协议的客户端进程

UDP协议的客户端进程

UDP协议的客户端进程分为五个部分:套接字建立、设置目的地址和端口、向服务器发送数据、从服务器接收数据、关闭套接字。流程如下:

(1)建立套接字文件描述符socket();

(2)设置服务器地址和端口,struct sockaddr;

(3)向服务器发送数据,send to();

(4)从服务器接收数据,recvfrom();

(5)关闭插座,关闭()。

linux下socket编程

UDP编程流程UDP编程过程

2、相关函数

(1) int socket(AF_INET,SOCK_DGRAM,0);

创建一个udp套接字并返回套接字描述符。UDP协议创建套接字的方式与TCP相同,使用socket()函数,只是协议类型使用SOCK_DGRAM而不是SOCK_STREAM。

(2) int sendto(int sockfd,const void *data,int data_len,unsigned int flags,struct sockaddr *remaddr,sock_lenremaddr_len)

功能:基于UDP发送数据报,返回发送数据的实际长度,出错返回-1。

参数描述:

Sockfd:套接字描述符

Data:指向要发送的数据的指针。

数据长度

标志:通常为0。

Remaddr:远程地址:IP地址和端口号。

Remaddr_len:地址长度

(3) int recvfrom(int sockfd,void *buf,int buf_len,unsigned int flags,struct sockaddr *from,sock _ len * from len);

函数:从UDP接收数据,返回实际接收的字节数,如果失败则返回-1。

参数描述:

Sockfd:套接字描述符

指向内存块的指针

Buf_len:内存块大小,以字节为单位。

标志:一般为0。

From:远程地址、IP地址和端口号。

Fromlen:远程地址长度

(4) ssize_t recv(int s,void*buf,size_t len,int flags);

连接的UDP可以调用recv从服务器读取数据。

ssize_tsend(int s,const void*buf,size_t len,int flags);

连接的UDP可以调用send向服务器发送数据。

3、UDPSocket客户服务器通信实例

根据通信流程,让我们实现一个UDP echo客户机/服务器。

服务器代码:

# include & ltstdio.h & gt# include & ltstdlib.h & gt# include & ltunistd.h & gt# include & lt错误号& gt# include & ltsys/types . h & gt;# include & ltsys/socket . h & gt;# include & ltnetinet/in . h & gt;# include & ltstring.h & gt# define my port 8887 # define ERR _ EXIT(m)\ do { \ perror(m);\ EXIT(EXIT _ FAILURE);\ } while(0)void echo _ ser(int sock){ char recvbuf[1024]= { 0 };结构sockaddr _ in peeraddrsocklen _ t peerlenint n;while(1){ peer len = sizeof(peer addr);memset(recvbuf,0,sizeof(recvbuf));n = recvfrom(sock,recvbuf,sizeof(recvbuf),0,(struct sockaddr *)&peeraddr,& peer len);如果(n & lt= 0){ if(errno = = EINTR)continue;ERR _ EXIT(& # 34;recvfrom错误& # 34;);} else if(n & gt;0){ printf(& # 34;接收的数据:% s \ n & # 34,recvbuf);sendto(sock,recvbuf,n,0,(struct sockaddr *)&peeraddr,peer len);printf(& # 34;发回的数据:% s \ n & # 34,recvbuf);} }关闭(sock);} int main(void){ int sock;if ((sock = socket(PF_INET,SOCK_DGRAM,0))& lt;0)ERR _ EXIT(& # 34;套接字错误& # 34;);struct sockaddr _ in servaddrmemset(&servaddr,0,sizeof(servaddr));servaddr.sin _ family = AF _ INETserv addr . sin _ port = htons(my port);serv addr . sin _ addr . s _ addr = htonl(in addr _ ANY);printf(& # 34;正在侦听端口% d \ n & # 34,my port);if (bind(sock,(struct sockaddr *)&servaddr,sizeof(servaddr))& lt;0)ERR _ EXIT(& # 34;绑定错误& # 34;);echo _ ser(sock);返回0;}客户代码:

# include & ltunistd.h & gt# include & ltsys/types . h & gt;# include & ltsys/socket . h & gt;# include & ltnetinet/in . h & gt;# include & ltarpa/inet . h & gt;# include & ltstdlib.h & gt# include & ltstdio.h & gt# include & lt错误号& gt# include & ltstring.h & gt# define my port 8887 char * SERVERIP = & # 34;127.0.0.1";# define ERR _ EXIT(m)\ do \ { \ perror(m);\ EXIT(EXIT _ FAILURE);\ } while(0)void echo _ CLI(int sock){ struct sockaddr _ in serva DDR;memset(&servaddr,0,sizeof(servaddr));servaddr.sin _ family = AF _ INETserv addr . sin _ port = htons(my port);serv addr . sin _ addr . s _ addr = inet _ addr(SERVERIP);int retchar send buf[1024]= { 0 };char recvbuf[1024]= { 0 };while (fgets(sendbuf,sizeof(sendbuf),stdin)!= NULL){ printf(& # 34;发送到服务器:% s \ n & # 34,sendbuf);sendto(sock,sendbuf,strlen(sendbuf),0,(struct sockaddr *)&servaddr,sizeof(servaddr));ret = recvfrom(sock,recvbuf,sizeof(recvbuf),0,NULL,NULL);if (ret == -1) { if (errno == EINTR)继续;ERR _ EXIT(& # 34;recvfrom & # 34);} printf(& # 34;从服务器接收:% s \ n & # 34,recvbuf);memset(sendbuf,0,sizeof(send buf));memset(recvbuf,0,sizeof(recvbuf));}关闭(袜子);} int main(void){ int sock;if ((sock = socket(PF_INET,SOCK_DGRAM,0))& lt;0)ERR _ EXIT(& # 34;插座& # 34;);echo _ CLI(sock);返回0;}实验结果:

UDP编程注意事项:

1.UDP消息可能会丢失或重复。

2.UDP消息可能有问题。

3.UDP缺乏流量控制。

4、UDP协议数据报文截断

5.recvfrom返回0,这并不意味着连接关闭,因为udp是无连接的。

6.ICMP异步错误

7、UDP连接

8.UDP出接口的确定

9.过大的UDP数据包可能带来的问题

因为UDP不需要维护连接,所以程序逻辑简单很多,但是UDP协议不可靠。其实有很多保证通信可靠性的机制需要在应用层实现,也就是前面提到的123点。例如,如果发送方很快,而接收方很慢,则很可能会生成ICMPSource抑制错误并丢弃一些数据包。

C/C++ Linux服务器架构师有必要学习私有信息“资料”(资料包括C/C++、Linux、golang技术、Nginx、ZeroMQ、MySQL、Redis、fastdfs、MongoDB、ZK、流媒体、CDN、P2P、K8S、Docker、TCP/IP、协诚、DPDK、ffmpeg等

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

发表回复

登录后才能评论