您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > Socket 编程 参考
Socket编程参考UNP第一卷chinaunix论坛一、基本知识主机字节序和网络字节序主机字节序即内存中存储字节的方法有:1.Littleendian:将低序字节存储在起始地址2.Bigendian:将高序字节存储在起始地址网络字序表示网络协议在处理多字节时的顺序,一律为bigendian主机字节序和网络字节序转换的函数:#includenetinet/in.huint16_thtons(uint16_t16位的主机字节序)uint32_thtonsl(uint32_t32位的主机字节序)//转换为网络字节序uint16_tntohs(uint16_t16位的网络字节序)uint32_tntohl(uint32_t32位的网络字节序)//转换为主机字节序缓冲区每个TCPSOCKET有一个发送缓冲区和一个接收缓冲区,TCP具有流量控制,所以接收缓冲区的大小就是通知另一端的窗口的大小,对方不会发大于该窗口大小的数据;而UDPSOCKET只有一个接收缓冲区无流量控制,当接收的数据报溢出时就会被丢弃通信域(地址族)套接字存在于特定的通信域(即地址族)中,只有隶属于同一地址族的套接字才能建立对话。Linux支持AF_INET(IPv4协议)、AF_INET6(IPv6协议)和AF_LOCAL(Unix域协议)。套接口(socket)=网络地址+端口号。,要建立一个套接口必须调用socket函数,套接口有三种类型,即字节流套接口(SOCK_STREAM),数据报套接口(SOCK_DGRAM)和原始套接口(SOCK_RAW)。定义一个连接的一个端点的两元组,即IP地址和端口号,称为一个套接口。在网络连接中,两个端点所组成的四元组(即本地IP、本地PORT、远程IP和远程PORT)称为socketpair,该四元组唯一的标识了一个网络连接。该情况可通过netstat验证。二、socket地址结构1.IPv4的Socket地址结构(定长)Structin_addr{In_addr_ts_addr;//32位IP地址,网络字节序}Structsockaddr_in{Uint8_tsin_len;//IPv4为固定的16字节长度Sa_family_tsin_family;//地址簇类型,为AF_INETIn_port_tsin_port;//16位端口号,网络字节序Structin_addrsin_addr;//32位IP地址Charsin_zero[8];//未用}2.IPv6的socket地址结构(定长)structin6_addr{uint8_ts6_addr[16];//128位IP地址,网络字节序}structsockaddr_in6{uint8_tsin6_len;//IPv6为固定的24字节长度sa_family_tsin6_family;//地址簇类型,为AF_INET6in_port_tsin6_port;//16位端口号,网络字节序uint32_tsin6_flowinfo;//32位流标签structin6_addrsin6_addr;//128位IP地址}3.UNIX域socket地址结构(变长)Structsockaddr_un,地址簇类型为AF_LOCAL4.数据链路socket地址结构(变长)structsockaddr_dl,地址簇类型为AF_LINK5.通用的socket地址结构structsockaddr{uint8_tsa_len;sa_family_tsa_family;charsa_data[14];}三、C/S网络编程初始化sock连接符:intsocket(intdomain,inttype,intprotocol);函数返回socket描述符,返回-1表示出错domain参数只能取AF_INET,protocol参数一般取0应用示例:TCP方式:sockfd=socket(AF_INET,SOCK_STREAM,0);UDP方式:sockfd=socket(AF_INET,SOCK_DGRAM,0);绑定端口:intbind(intsockfd,structsockaddr*sa,intaddrlen);函数返回-1表示出错,最常见的错误是该端口已经被其他程序绑定。需要注意的一点:在Linux系统中,1024以下的端口只有拥有root权限的程序才能绑定。连接网络(用于TCP方式):intconnect(intsockfd,structsockaddr*servaddr,intaddrlen);函数返回-1表示出错,可能是连接超时或无法访问。返回0表示连接成功,可以通过sockfd传输数据了。监听端口(用于TCP方式):intlisten(intsockfd,intqueue_length);需要在此前调用bind()函数将sockfd绑定到一个端口上,否则由系统指定一个随机的端口。接收队列:一个新的Client的连接请求先被放在接收队列中,直到Server程序调用accept函数接受连接请求。第二个参数queue_length,指的就是接收队列的长度也就是在Server程序调用accept函数之前最大允许的连接请求数,多余的连接请求将被拒绝。响应连接请求(用于TCP方式):intaccept(intsockfd,structsockaddr*addr,int*addrlen);accept()函数将响应连接请求,建立连接并产生一个新的socket描述符来描述该连接,该连接用来与特定的Client交换信息。函数返回新的连接的socket描述符,错误返回-1addr将在函数调用后被填入连接对方的地址信息,如对方的IP、端口等。addrlen作为参数表示addr内存区的大小,在函数返回后将被填入返回的addr结构的大小。accept缺省是阻塞函数,阻塞直到有连接请求应用示例:structsockaddr_intheir_addr;/*用于存储连接对方的地址信息*/intsin_size=sizeof(structsockaddr_in);……(依次调用socket(),bind(),listen()等函数)new_fd=accept(sockfd,&their_addr,&sin_size);printf(”对方地址:%s\n,inet_ntoa(their_addr.sin_addr));……关闭socket连接:intclose(intsockfd);关闭连接将中断对该socket的读写操作。关闭用于listen()的socket描述符将禁止其他Client的连接请求。部分关闭socket连接:intshutdown(intsockfd,inthow);Shutdown()函数可以单方面的中断连接,即禁止某个方向的信息传递。参数how:0-禁止接收信息1-禁止发送信息2-接收和发送都被禁止,与close()函数效果相同socket轮询选择:intselect(intnumfds,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout);应用于多路同步I/O模式(将在同步工作模式中详细讲解)FD_ZERO(*set)清空socket集合FD_SET(s,*set)将s加入socket集合FD_CLR(s,*set)从socket集合去掉sFD_ISSET(s,*set)判断s是否在socket集合中常数FD_SETSIZE:集合元素的最多个数等待选择机制:intpoll(structpollfd*ufds,unsignedintnfds,inttimeout);是select机制的一个变种,应用于多路同步I/O模式(将在同步工作模式中详细讲解)ufds是pollfd结构的数组,数组元素个数为nfds。structpollfd{intfd;/*文件描述字*/shortevents;/*请求事件集合*/shortrevents;/*返回时间集合*/};接收/发送消息:TCP方式:intsend(ints,constvoid*buf,intlen,intflags);intrecv(ints,void*buf,intlen,intflags);函数返回实际发送/接收的字节数,返回-1表示出错,需要关闭此连接。函数缺省是阻塞函数,直到发送/接收完毕或出错注意:如果send函数返回值与参数len不相等,则剩余的未发送信息需要再次发送UDP方式:intsendto(ints,constvoid*buf,intlen,intflags,conststructsockaddr*to,inttolen);intrecvfrom(ints,void*buf,intlen,intflags,structsockaddr*from,int*fromlen);与TCP方式的区别:需要指定发送/接收数据的对方(第五个参数to/from)函数返回实际发送/接收的字节数,返回-1表示出错。函数缺省是阻塞函数,直到发送/接收完毕或出错注意:如果send函数返回值与参数len不相等,则剩余的未发送信息需要再次发送注意,网络字节流的读写不同于文件的读写,由于socket缓冲的因素,可能读写的字节数小于所指定的字节数。所以可以使用如下函数:ssize_treadn(intfd,void*buf,size_tn){ssize_tnleft;ssize_tnread;char*ptr;ptr=buf;nleft=n;while(nleft0){if((nread=read(fd,ptr,nleft))0){if(errno==EINTR)nread=0;elsereturn(-1);}elseif(nread==0)//EOFbreak;nleft-=nread;ptr+=nread;}return(n-nleft);}ssize_twritten(intfd,constvoid*buf,size_tn){ssize_tnleft;ssize_tnwrite;constchar*ptr;ptr=buf;nleft=n;while(nleft0){if(nwrite=write(fd,ptr,left)=0){if(errno==EINTR){nwrite=0;elsereturn(-1);}nleft-=nwrite;ptr+=nwrite;}return(n);}基于消息的方式:intsendmsg(ints,conststructmsghdr*msg,intflags);intrecvmsg(ints,structmsghdr*msg,intflags);标志位:上面这六个发送/接收函数均有一个参数flags,用来指明数据发送/接收的标志,常用的标志主要有:MSG_PEEK对数据接收函数有效,表示读出网络数据后不清除已读的数据MSG_WAITALL对数据接收函数有效,表示一直执行直到buf读满、socket出错或者程序收到信号。MSG_DONTWAIT对数据发送函数有效,表示不阻塞等待数据发送完后返回,而是直接返回。(只对非阻塞socket有效)MSG_NOSIGNAL对发送接收函数有效,表示在对方关闭连接后出错但不发送SIGPIPE信号给程序。MSG_OOB对发送接收都有效,表示读/写带外数据(out-of-banddata)IP地址字符串和网络字节序的二进制IP地址相互转换的函数:#inlcudearpa/inet.hintinet_aton(constchar*IP地址字符串,structin_addr*32位的网络字节序形式的IP地址)成功—1失败—0[通用地址函数]intinet_pton(int地址簇类型,可以是AF_INET/AF_INET6,constchar*IP地址字符串,void*32位的网络字节序形式的IP地址)成功—1格式错误—0失败—0in_addr_tinet
本文标题:Socket 编程 参考
链接地址:https://www.777doc.com/doc-5230130 .html