Socket 编程 参考.pdf
《Socket 编程 参考.pdf》由会员分享,可在线阅读,更多相关《Socket 编程 参考.pdf(29页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、Socket 编程 Socket 编程 参考 UNP 第一卷 chinaunix 论坛 一、基本知识 一、基本知识 主机字节序和网络字节序 主机字节序和网络字节序 主机字节序即内存中存储字节的方法有:1 Little endian:将低序字节存储在起始地址 2 Big endian:将高序字节存储在起始地址 网络字序表示网络协议在处理多字节时的顺序,一律为 big endian 主机字节序和网络字节序转换的函数:#include uint16_t htons(uint16_t)uint32_t htonsl(uint32_t)/转换为网络字节序 uint16_t ntohs(uint16_t)
2、uint32_t ntohl(uint32_t)/转换为主机字节序 缓冲区 缓冲区 每个 TCP SOCKET 有一个发送缓冲区和一个接收缓冲区,TCP 具有流量控制,所以接收缓冲区的大小就是通知另一端的窗口的大小,对方不会发大于该窗口大小的数据;而 UDP SOCKET 只有一个接收缓冲区无流量控制,当接收的数据报溢出时就会被丢弃 通信域(地址族)通信域(地址族)套接字存在于特定的通信域(即地址族)中,只有隶属于同一地址族的套接字才能建立对话。Linux 支持 AF_INET(IPv4 协议)、AF_INET6(IPv6 协议)和 AF_LOCAL(Unix 域协议)。套接口(socket)
3、网络地址+端口号。,要建立一个套接口必须调用 socket 函数,套接口有三种类型,即字节流套接口(SOCK_STREAM),数据报套接口(SOCK_DGRAM)和原始套接口(SOCK_RAW)。定义一个连接的一个端点的两元组,即 IP 地址和端口号,称为一个套接口。在网络连接中,两个端点所组成的四元组(即本地 IP、本地 PORT、远程 IP 和远程 PORT)称为 socket pair,该四元组唯一的标识了一个网络连接。该情况可通过 netstat 验证。二、socket 地址结构 1二、socket 地址结构 1 IPv4 的 Socket 地址结构(定长)IPv4 的 Socket
4、地址结构(定长)Struct in_addr In_addr_t s_addr;/32 位 IP 地址,网络字节序 Struct sockaddr_in Uint8_t sin_len;/IPv4 为固定的 16 字节长度 Sa_family_t sin_family;/地址簇类型,为 AF_INET In_port_t sin_port;/16 位端口号,网络字节序 Struct in_addr sin_addr;/32 位 IP 地址 Char sin_zero8;/未用 22 IPv6 的 socket 地址结构(定长)IPv6 的 socket 地址结构(定长)struct in6_a
5、ddr uint8_t s6_addr16;/128 位 IP 地址,网络字节序 struct sockaddr_in6 uint8_t sin6_len;/IPv6 为固定的 24 字节长度 sa_family_t sin6_family;/地址簇类型,为 AF_INET6 in_port_t sin6_port;/16 位端口号,网络字节序 uint32_t sin6_flowinfo;/32 位流标签 struct in6_addr sin6_addr;/128 位 IP 地址 3 3 UNIX 域 socket 地址结构(变长)UNIX 域 socket 地址结构(变长)Struct
6、sockaddr_un,地址簇类型为 AF_LOCAL 4 4 数据链路 socket 地址结构(变长)数据链路 socket 地址结构(变长)struct sockaddr_dl,地址簇类型为 AF_LINK 5 5 通用的 socket 地址结构 通用的 socket 地址结构 struct sockaddr uint8_t sa_len;sa_family_t sa_family;char sa_data14;三、C/S 网络编程 三、C/S 网络编程 初始化 sock 连接符:int socket(int domain,int type,int protocol);函数返回 socke
7、t 描述符,返回-1 表示出错 domain 参数只能取 AF_INET,protocol 参数一般取 0 应用示例:TCP 方式:sockfd=socket(AF_INET,SOCK_STREAM,0);UDP 方式:sockfd=socket(AF_INET,SOCK_DGRAM,0);绑定端口:int bind(int sockfd,struct sockaddr*sa,int addrlen);函数返回-1 表示出错,最常见的错误是该端口已经被其他程序绑定。需要注意的一点:在 Linux 系统中,1024 以下的端口只有拥有 root 权限的程序才能绑定。连接网络(用于 TCP 方式)
8、:int connect(int sockfd,struct sockaddr*servaddr,int addrlen);函数返回-1 表示出错,可能是连接超时或无法访问。返回 0 表示连接成功,可以通过 sockfd 传输数据了。监听端口(用于 TCP 方式):int listen(int sockfd,int queue_length);需要在此前调用 bind()函数将 sockfd 绑定到一个端口上,否则由系统指定一个随机的端口。接收队列:一个新的 Client 的连接请求先被放在接收队列中,直到 Server 程序调用 accept 函数接受连接请求。第二个参数 queue_len
9、gth,指的就是接收队列的长度 也就是在 Server 程序调用 accept 函数之前最大允许的连接请求数,多余的连接请求将被拒绝。响应连接请求(用于 TCP 方式):int accept(int sockfd,struct sockaddr*addr,int*addrlen);accept()函数将响应连接请求,建立连接并产生一个新的 socket 描述符来描述该连接,该连接用来与特定的 Client 交换信息。函数返回新的连接的 socket 描述符,错误返回-1 addr 将在函数调用后被填入连接对方的地址信息,如对方的 IP、端口等。addrlen 作为参数表示 addr 内存区的大
10、小,在函数返回后将被填入返回的 addr 结构的大小。accept 缺省是阻塞函数,阻塞直到有连接请求 应用示例:struct sockaddr_in their_addr;/*用于存储连接对方的地址信息*/int sin_size=sizeof(struct sockaddr_in);(依次调用 socket(),bind(),listen()等函数)new_fd=accept(sockfd,&their_addr,&sin_size);printf(”对方地址:%sn,inet_ntoa(their_addr.sin_addr);关闭 socket 连接:int close(int soc
11、kfd);关闭连接将中断对该 socket 的读写操作。关闭用于 listen()的 socket 描述符将禁止其他 Client 的连接请求。部分关闭 socket 连接:int shutdown(int sockfd,int how);Shutdown()函数可以单方面的中断连接,即禁止某个方向的信息传递。参数 how:0-禁止接收信息 1-禁止发送信息 2-接收和发送都被禁止,与 close()函数效果相同 socket 轮询选择:int select(int numfds,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,struct ti
12、meval*timeout);应用于多路同步 I/O 模式(将在同步工作模式中详细讲解)FD_ZERO(*set)清空 socket 集合 FD_SET(s,*set)将 s 加入 socket 集合 FD_CLR(s,*set)从 socket 集合去掉 s FD_ISSET(s,*set)判断 s 是否在 socket 集合中 常数 FD_SETSIZE:集合元素的最多个数 等待选择机制:int poll(struct pollfd*ufds,unsigned int nfds,int timeout);是 select 机制的一个变种,应用于多路同步 I/O 模式(将在同步工作模式中详细
13、讲解)ufds 是 pollfd 结构的数组,数组元素个数为 nfds。struct pollfd int fd;/*文件描述字*/short events;/*请求事件集合*/short revents;/*返回时间集合*/;接收/发送消息:TCP 方式:int send(int s,const void*buf,int len,int flags);int recv(int s,void*buf,int len,int flags);函数返回实际发送/接收的字节数,返回-1 表示出错,需要关闭此连接。函数缺省是阻塞函数,直到发送/接收完毕或出错 注意:如果 send 函数返回值与参数 le
14、n 不相等,则剩余的未发送信息需要再次发送 UDP 方式:int sendto(int s,const void*buf,int len,int flags,const struct sockaddr*to,int tolen);int recvfrom(int s,void*buf,int len,int flags,struct sockaddr*from,int*fromlen);与 TCP 方式的区别:需要指定发送/接收数据的对方(第五个参数 to/from)函数返回实际发送/接收的字节数,返回-1 表示出错。函数缺省是阻塞函数,直到发送/接收完毕或出错 注意:如果 send 函数返回
15、值与参数 len 不相等,则剩余的未发送信息需要再次发送 注意,网络字节流的读写不同于文件的读写,由于 socket 缓冲的因素,可能读写的字节数小于所指定的字节数。所以可以使用如下函数:ssize_t readn(int fd,void*buf,size_t n)ssize_t nleft;ssize_t nread;char*ptr;ptr=buf;nleft=n;while(nleft 0)if(nread=read(fd,ptr,nleft)0)if(nwrite=write(fd,ptr,left)=0)if(errno=EINTR)nwrite=0;else return(-1);
16、nleft-=nwrite;ptr+=nwrite;return(n);基于消息的方式:int sendmsg(int s,const struct msghdr*msg,int flags);int recvmsg(int s,struct msghdr*msg,int flags);标志位:上面这六个发送/接收函数均有一个参数 flags,用来指明数据发送/接收的标志,常用的标志主要有:MSG_PEEK 对数据接收函数有效,表示读出网络数据后不清除已读的数据 MSG_WAITALL 对数据接收函数有效,表示一直执行直到 buf 读满、socket 出错或者程序收到信号。MSG_DONTWA
17、IT 对数据发送函数有效,表示不阻塞等待数据发送完后返回,而是直接返回。(只对非阻塞 socket 有效)MSG_NOSIGNAL 对发送接收函数有效,表示在对方关闭连接后出错但不发送 SIGPIPE 信号给程序。MSG_OOB 对发送接收都有效,表示读/写带外数据(out-of-band data)IP 地址字符串和网络字节序的二进制 IP 地址相互转换的函数:IP 地址字符串和网络字节序的二进制 IP 地址相互转换的函数:#inlcude int inet_aton(const char*,struct in_addr*)成功1 失败0 通用地址函数int inet_pton(int,可以
18、是 AF_INET/AF_INET6,const char*,void*)成功1 格式错误0 失败0 in_addr_t inet_addr(const char*)返回 32 位网络字节序的 IP 地址,失败INADDR_NONE char*inet_ntoa(struct in_addr)返回 IP 地址字符串 const char*inet_ntop(int,const void*,char*,size_t )返回指向结果的指针 字节顺序转换 htons()-Host to Network Short htonl()-Host to Network Long ntohs()-Networ
19、k to Host Short ntohl()-Network to Host Long 连接过程是通过一系列状态表示的,这些状态有:LISTEN,SYN-SENT,SYN-RECEIVED,ESTABLISHED,FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT 和 CLOSED。CLOSED 表示没有连接,各个状态的意义如下:LISTEN-侦听来自远方 TCP 端口的连接请求;SYN-SENT-在发送连接请求后等待匹配的连接请求;SYN-RECEIVED-在收到和发送一个连接请求后等待对连接请求的确认;ESTABLISH
20、ED-代表一个打开的连接,数据可以传送给用户;FIN-WAIT-1-等待远程 TCP 的连接中断请求,或先前的连接中断请求的确认;FIN-WAIT-2-从远程 TCP 等待连接中断请求;CLOSE-WAIT-等待从本地用户发来的连接中断请求;CLOSING-等待远程 TCP 对连接中断的确认;LAST-ACK-等待原来发向远程 TCP 的连接中断请求的确认;TIME-WAIT-等待足够的时间以确保远程 TCP 接收到连接中断请求的确认;CLOSED-没有任何连接状态;Tcp 面向连接 如下图所示:Socket()Server(主动打开)Bind()Listen()Accept()Socket(
21、)Client(被动打开)Connect()Write()Read()Read()Write()Close()Read()Close()#include int socket(int,int,int protocol)非负整数表示socket描述字-成功-1-失败#include int connect(int socket描述 字 ,c o n s t s t r u c ts o c k a d d r *服 务 器 的SOCKET地址,socklen_t 服务器的SOCKET地址结构长度)0成功1失败#include int bind(int,const structsockaddr*,
22、socklen_t)0-成功1-失败若SOCKET地址中:IP地址为通配地址INADDR_ANY(0),或PORT为0,都表示为让内核选择#include int listen(int,int)成功-1-出错3进入未完成连接队列中,SYN_RCVD状态4转入已完成队列队列中,ESTABLISHED状态#include int accept(int,structsockaddr*,socklen_t*)非负描述字(已连接套接口)-成功-1-出错2SYN_SENT状态1CLOSED状态3ESTABLISHED状态4FIN_WAIT1状态5FIN_WAIT2状态6TIME_WAIT状态7CLOSED
23、状态TIMEOUT=2MSL(max segementlifetime 1-4分钟)1CLOSED状态2LISTEN状态5CLOSED_WAIT6LAST_ACK7CLOSED TIME_WAIT 状态 一个 tcp 协议的 socket 编程例子:Server Server/*主函数*/int listenfd,connfd;struct sockaddr_in servaddr,cliaddr;struct hostent*hp;struct servent*sp;struct in_addr*pptr;if(hp=gethostbyname(argv1)=NULL)/error if(s
24、p=getservbyname(argv2,“tcp”)=NULL)/error pptr=(struct in_addr*)hp-h_addr_list;listenfd=socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr);servaddr.sin_family=AF_INET;/servaddr.sin_addr.s_addr=htonl(INADDR_ANY);memcpy(&servaddr.sin_addr,*pptr,sizeof(struct in_addr);servaddr.sin_port=htons
25、(portnum);bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr);listen(listenfd,listenqueuenum);signal(SIGCHLD,sig_chld);for(;)len=sizeof(cliaddr);if(connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&len)0);return;client client sockfd=socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servad
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Socket 编程 参考
限制150内