您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > Linux网络程序设计
网络程序设计第8章第2页Socket网络协议的作用协议栈实现:传输层和传输层以下协议在内核中实现UNIX提供给应用程序使用网络功能的方法将设备和通信管道组织成文件方式,创建方式不同,访问方法相同终端设备管道通信服务SocketTLI编程接口Socket编程接口面向网络通信,不仅仅用于TCP/IP利用虚拟loopback接口(127.0.0.1),可实现同台计算机进程间通信第8章第3页TCP与UDPTCP面向连接可靠字节流传输不保证报文边界UDP面向数据报不可靠错报,丢报,重报,乱序,流量控制数据报传输广播和组播第8章第4页网络字节顺序CPU字节顺序BigEndian(大尾)PowerPC,SPARC,MotorolaLittleEndian(小尾)IntelX86网络字节顺序与X86相反网络字节转换的库函数htonlntohl四字节整数(long)htonsntohs两字节整数(short)TCP客户-服务器程序TCP套接字编程socket()bind()listen()accept()read()write()close()socket()connect()write()read()close()阻塞直到接收到客户连接请求服务器端客户端建立连接TCP三次握手处理请求数据请求数据响应关闭连接第8章第7页客户端程序:client.c(1)#defineSIZE8192#definePORT_NO12345intmain(intargc,char*argv[]){intsock,len;structsockaddr_inname;unsignedcharsbuf[SIZE];if(argc2)...sock=socket(AF_INET,SOCK_STREAM,0);if(sock0)...name.sin_family=AF_INET;name.sin_addr.s_addr=htonl(inet_network(argv[1]));name.sin_port=htons(PORT_NO);if(connect(sock,&name,sizeof(name))0){perror(\nconnectingserverstreamsocket);exit(1);}printf(Connected.\n);第8章第8页客户端程序:client.c(2)for(;;){if(fgets(sbuf,SIZE,stdin)==NULL)break;if(write(sock,sbuf,strlen(sbuf))0){perror(sendingstreammessage);exit(1);}}close(sock);printf(Connectionclosed.\n\n);exit(0);}第8章第9页客户端程序创建文件描述符socket建立连接connect进程阻塞,等待三次握手成功端点名的概念:IP地址+端口号本地端点名远端端点名发送数据发送速率大于通信速率,进程会被阻塞关闭连接第8章第10页服务端程序:server0.c(1)#definePORT_NO12345intmain(void){intadmin_sock,data_sock,nbyte,i;structsockaddr_inname;charbuf[8192];admin_sock=socket(AF_INET,SOCK_STREAM,0);name.sin_family=AF_INET;name.sin_addr.s_addr=INADDR_ANY;name.sin_port=htons(PORT_NO);bind(admin_sock,&name,sizeof(name));listen(admin_sock,5);data_sock=accept(admin_sock,0,0);printf(Acceptconnection\n);第8章第11页服务端程序:server0.c(2)for(;;){nbyte=read(data_sock,buf,sizeof(buf));if(nbyte==0){printf(***Disconnected.\n);close(data_sock);exit(0);}for(i=0;inbyte;i++)printf(%c,buf[i]);}}第8章第12页服务端程序创建文件描述符socketbind设定本地端点名也可以用在客户端程序Listen进程不会在此被阻塞,仅仅给内核一个通知accept进程会在这里阻塞等待新连接到来创建新进程时的文件描述符处理问题:不能同时接纳多个连接解决方法多进程并发处理单进程并发处理第8章第13页多进程并发:server1.c(1)#definePORT_NO12345intmain(void){intadmin_sock,data_sock,pid,name_len;structsockaddr_inname,peer;admin_sock=socket(AF_INET,SOCK_STREAM,0);if(admin_sock0){perror(createstreamsocket);exit(1);}name.sin_family=AF_INET;name.sin_addr.s_addr=INADDR_ANY;name.sin_port=htons(PORT_NO);if(bind(admin_sock,&name,sizeof(name))0){perror(bindingstreamsocket);exit(1);}listen(admin_sock,5);signal(SIGCLD,SIG_IGN);第8章第14页多进程并发:server1.c(2)for(;;){name_len=sizeof(peer);data_sock=accept(admin_sock,&peer,&name_len);if(data_sock0)continue;printf(Acceptconnectionfrom%s:%d\n,inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));pid=fork();if(pid0){/*parrentprocess*/close(data_sock);/*不可省略*/}elseif(pid==0){/*childprocess*/charfd_str[16];close(admin_sock);sprintf(fd_str,%d,data_sock);execlp(./server1a,./server1a,fd_str,0);perror(execlp);exit(1);}}}第8章第15页多进程并发:server1a.c(1)intmain(intargc,char*argv[]){structsockaddr_inpeer;unsignedcharbuf[8192];intnbyte,i,sock,name_len=sizeof(peer);sock=strtol(argv[1],0,0);getpeername(sock,&peer,&name_len);for(;;){nbyte=read(sock,buf,sizeof(buf));printf(%s:%d,inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));if(nbyte0){perror(Receivingpacket);exit(1);}elseif(nbyte==0){printf(***Disconnected.\n);close(sock);exit(0);}for(i=0;inbyte;i++)printf(%c,buf[i]);}}第8章第16页socket系统调用socket创建文件描述符socket,端点名未指定bind设定本地端点名,也可以用在客户端程序listen开始监听到达的连接请求accept接受一个连接请求connect建立连接,设定远端端点名close关闭连接,释放文件描述符第8章第17页read/write系统调用(1)read/write与TCP通信的时序例:主机A用write()通过TCP连接向B发送数据,B接收数据用read()t0:主机B开始read()t1:主机A调用write(),TCP发送缓冲区有空闭,数据拷贝至发送缓冲区t2:主机A将数据发往主机Bt3:主机B收到数据后,验证校验和正确t4:主机B向主机A发ACK,ACK途中丢失t5:主机A超时自动重发数据t6:主机B收到重复的数据后扔掉,回送ACKt7:主机A收到ACK,将发送缓冲区的数据清除write在t1返回,read在t3返回第8章第18页read/write系统调用(2)read/write与TCP通信故障和流控流控问题断线对方重启动Keepalive(默认两小时)getsockopt/setsockopt可以设置保活间隔,重传次数,重传时间“粘连问题”read/write与UDP通信网络故障没有数据粘连没有流控功能不可靠第8章第19页端点名相关的系统调用getpeername获取对方的端点名getpeername(intsockfd,structsockaddr*name,int*namelen);getsockname获取本地的端点名getsockname(intsockfd,structsockaddr*name,int*namelen);第8章第20页read/write的其他版本intrecv(intsockfd,void*buf,intnbyte,intflags);intrecvfrom(intsockfd,void*buf,intnbyte,intflags,structsockaddr*from,int*fromlen);intsend(intsockfd,void*buf,intnbyte,intflags);intsendto(intsockfd,void*buf,intnbyte,intflags,structsockaddr*to,inttolen);recvfrom/sendto可以指定对方的端点名,常用于UDPWinsock只能用recv/send不可用read/write第8章第21页shutdown系统调用(1)intshutdown(intsockfd,inthowto);禁止发送或接收。socket提供全双工通信,两个方向上都可以收发数据,shutdown提供了对于一个方向的通信控制参数howto取值SHUT_RD:不能再接收数据,随后read均返回0SHUT_WR:不能再发送数据,本方向再次write会导致SIGPIPE信号SHUT_RDWR:禁止这个sockfd上的任何收发第8章第22页shutdown系统调用(2)shutdown是通用的套接字上的操作执行后对通信的影响,会与具体的通信协议相关TCP协议允许关闭发送方向的半个连接没有一种机制让对方关闭它的发送,但TCP协议的流量控制机制,可以通知对方自己的接收窗口为0,对方的write会继续,并将数据堆积在发送缓冲区UDP协议UDP关闭接收方向内核仅记下一个标记,不再提供数据,但无法阻止对方的发送而导致的网络上数据即使套接字关闭也不影响对方发出无人接收的数据报第8章第23页socket控制Socket控制intgetsockopt(intsokfd,intlevel,intoptname,void*optval,int*optlen);intsetsockopt(intsockfd,intlevel,intoptname,void*optval,intoptlen);intioctl(
本文标题:Linux网络程序设计
链接地址:https://www.777doc.com/doc-4713186 .html