UNIX网络编程笔记 第八章 基本UDP套接字编程
2016-09-16 12:55
211 查看
recvfrom和sendto函数:
udp的异步错误:
如果udp客户端向一个服务进程未启动的服务端发送数据,虽然网络会返回一个端口不可达错误,但是客户端进程的sendto并不会返回错误,而是返回成功(因为udp输出操作成功返回,仅仅代表在接口输出队列中具有存放该IP数据报的空间,但是ICMP错误要更晚一些时候才返回,这就是称其为异步的原因)。
一个几本原则是:对于一个udp套接字,由它引发的异步错误并不返回给它,除非它已连接(调用connect函数)
示例代码:
:
#include <sys/socket.h> ssize_t recvfrom(int sockfd,void *buf,size_t nbytes,int flags,struct sockaddr *from,socklen_t *addrlen); ssize_t sendto(int sockfd,void *buf,size_t nbytes,int flags,struct sockaddr *to,socklen_t addrlen); //若成功则返回读或写的字节数,若出错返回-1 //tcp套接字read时返回0代表连接已关闭;udp套接字则不然,recvfrom返回0是一种正常状态
udp的异步错误:
如果udp客户端向一个服务进程未启动的服务端发送数据,虽然网络会返回一个端口不可达错误,但是客户端进程的sendto并不会返回错误,而是返回成功(因为udp输出操作成功返回,仅仅代表在接口输出队列中具有存放该IP数据报的空间,但是ICMP错误要更晚一些时候才返回,这就是称其为异步的原因)。
一个几本原则是:对于一个udp套接字,由它引发的异步错误并不返回给它,除非它已连接(调用connect函数)
示例代码:
:
//server.c #include "common.h" #include <poll.h> #include <limits.h> int main(int argc, char **agrv){ int tcpsockfd,udpsockfd,tcpclientfd; struct sockaddr_in serveraddr,clientaddr; socklen_t addrlen = sizeof(clientaddr); bzero(&serveraddr,sizeof(serveraddr)); bzero(&clientaddr,sizeof(clientaddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(45000); inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr); tcpsockfd = socket(AF_INET,SOCK_STREAM,0); bind(tcpsockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr)); listen(tcpsockfd,20); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(45000); inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr); udpsockfd = socket(AF_INET,SOCK_DGRAM,0); bind(udpsockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr)); struct pollfd allsockets[OPEN_MAX]; for(int i = 0; i < OPEN_MAX; i ++){ allsockets[i].fd = -1; } allsockets[0].fd = tcpsockfd; allsockets[0].events = POLLRDNORM; allsockets[1].fd = udpsockfd; allsockets[1].events = POLLRDNORM; int maxi = 1; int i; char buf[800]; while(1){ int newMaxi = 0; for(int i = 0; i <= maxi; i++){ if(allsockets[i].fd != -1) newMaxi = i; } maxi = newMaxi; int nready = poll(allsockets,maxi+1,-1); if(allsockets[0].revents & (POLLRDNORM | POLLERR)){ tcpclientfd = accept(tcpsockfd,(struct sockaddr*)&clientaddr,&addrlen); if(tcpclientfd < 0){ if(errno == EINTR){ ; }else{ puts("accept error"); } }else{ for(i = 2; i < OPEN_MAX; i++){ if(allsockets[i].fd == -1){ allsockets[i].fd = tcpclientfd; allsockets[i].events = POLLRDNORM; maxi = MAX(maxi,i); break; } } } nready--; } if(allsockets[1].revents & POLLRDNORM){ int readnum = recvfrom(udpsockfd,buf,sizeof(buf),0,(struct sockaddr*)&clientaddr,&addrlen); printf("read %d bytes from udp client\n",readnum); if(readnum < 0){ close(udpsockfd); puts("read from udpclient error"); }else{ buf[readnum] = 0; printf("%s",buf); int sendnum = sendto(udpsockfd,buf,strlen(buf),0,(struct sockaddr*)&clientaddr,addrlen); if(sendnum < 0) err_sys("udp send error"); else printf("%d bytes sent\n",readnum); } nready--; } for(i = 2; i <= maxi; i++){ int tcpclientfd = allsockets[i].fd; if(tcpclientfd != -1 && (allsockets[i].revents & POLLRDNORM)){ int readnum = read(tcpclientfd,buf,sizeof(buf)); buf[readnum] = 0; if(readnum < 0){ if(errno == EINTR){ continue; }else{ close(tcpclientfd); allsockets[i].fd = -1; puts("rad error"); } }else if (readnum == 0){ close(tcpclientfd); allsockets[i].fd = -1; puts("tcp client close socket"); }else{ printf("%s",buf); int writenum = write(tcpclientfd,buf,readnum); if(writenum < 0){ err_sys("write error"); }else{ printf("%d bytes sent\n",readnum); } } if(--nready <= 0) break; } } } }
//client.c #include "common.h" int main(int argc, char **argv){ int sockfd; struct sockaddr_in serveraddr,clientaddr; char buf[100]; bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family = AF_INET; inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr); serveraddr.sin_port = htons(45000); bzero(&clientaddr,sizeof(clientaddr)); sockfd = socket(AF_INET,SOCK_DGRAM,0); int rtn = connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr)); if(rtn != 0){ err_sys("connect error"); } fd_set readset; FD_ZERO(&readset); FD_SET(sockfd,&readset); int sockStdin = fileno(stdin); FD_SET(fileno(stdin),&readset); int stdineof = 0; while (1) { FD_SET(sockfd,&readset); int maxfd = sockfd; if(stdineof == 0) { FD_SET(sockStdin,&readset); maxfd = MAX(sockfd,fileno(stdin)); } int nReady = select(maxfd + 1,&readset,NULL,NULL,NULL); printf("nReady = %d\n",nReady); socklen_t addrlen = sizeof(clientaddr); if(nReady > 0){ if(FD_ISSET(sockStdin,&readset)){ puts("read from stdin"); int readNum = read(sockStdin,buf,sizeof(buf)); if(readNum == 0){ puts("eof, close socket"); shutdown(sockfd,1); FD_CLR(sockStdin,&readset); stdineof = 1; continue; } //int sendnum = sendto(sockfd,buf,readNum,0,(struct sockaddr*)&serveraddr,addrlen); int sendnum = write(sockfd,buf,readNum); if(sendnum < 0) err_sys("sendto error"); printf("%d bytes sent\n",sendnum); } if(FD_ISSET(sockfd,&readset)){ puts("read from server"); //int readNum = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&serveraddr,&addrlen); int readNum = read(sockfd,buf,sizeof(buf)); if(readNum == 0){ if(stdineof == 1) { puts("server close socket"); return 0; } else err_sys("client read error"); } write(fileno(stdout),buf,readNum); } } } return 0; }
相关文章推荐
- Unix网络编程代码 第8章 基本UDP套接字编程
- 《UNIX网络编程 卷1》 笔记: 基本UDP套接字编程
- UNIX网络编程 第8章 基本UDP套接字编程
- 黑马程序员-------Java笔记--------网络编程(UDP与TCP基本步骤)
- C++入门经典 笔记 (第八章)创建基本类
- UNIX网络编程卷一 笔记 第四章 基本TCP套接字编程
- 基本UDP套接字编程
- UNP函数笔记七: 基本SCTP套接字编程
- UNIX网络编程笔记(6)—UDP网络编程
- Unix网络编程学习笔记之第8章 基于UDP套接字编程
- 王爽《汇编语言》(第二版) 学习笔记 (第八章 数据处理的两个基本问题 )
- 【unix网络编程第三版】阅读笔记(三):基本套接字编程
- UDP基本协议学习笔记
- [置顶] [汇编学习笔记][第八章数据处理的两个基本问题]
- 网络编程学习——基本UDP套接字编程
- 《UNIX网络编程》学习笔记:基本TCP套接字编程
- UNP函数笔记六: 基本UDP套接字编程
- Unix网络编程—基本UDP套接字编程
- UDP 第四章基本套接字编程
- SPRING IN ACTION 第4版笔记-第八章Advanced Spring MVC-003-Pizza例子的基本流程