您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 信息化管理 > 面向连接的套接字通信-socket编程
第1页共26页面向连接的套接字通信1.1面向连接的套接字通信工作流程为了实现服务器与客户机的通信,服务器和客户机都必须建立套接字。服务器与客户机的工作原理可以用下面的过程来描述。(1)服务器先用socket函数来建立一个套接字,用这个套接字完成通信的监听。(2)用bind函数来绑定一个端口号和IP地址。因为本地计算机可能有多个网址和IP,每一个IP和端口有多个端口。需要指定一个IP和端口进行监听。(3)服务器调用listen函数,使服务器的这个端口和IP处于监听状态,等待客户机的连接。(4)客户机用socket函数建立一个套接字,设定远程IP和端口。(5)客户机调用connect函数连接远程计算机指定的端口。(6)服务器用accept函数来接受远程计算机的连接,建立起与客户机之间的通信。(7)建立连接以后,客户机用write函数向socket中写入数据。也可以用read函数读取服务器发送来的数据。(8)服务器用read函数读取客户机发送来的数据,也可以用write函数来发送数据。(9)完成通信以后,用close函数关闭socket连接。客户机与服务器建立面向连接的套接字进行通信,请求与响应过程可用图来表示。1.1.1套接口地址结构第2页共26页IPV4套接口地址结构IPV4套接口地址结构通常也称为“网际套接口地址结构”,它以“sockaddr_in”命名,定义在头文件netinet/in.h。通用套接口地址结构structsockaddr{uint8_tsa_len;sa_family_tsa_family;charsa_data[14];}第3页共26页1.1.2socket函数为了执行网络I/O,一个进程必须做的第一件事情就是调用socet函数,指定期望的通信协议类型。第4页共26页参数:其中family参数指明协议族,是下图中的某个常值。该参数也被称为协议域(domain)。Type参数指明套接口类型,是下图中的某个常值。Protocol参数应设为下图所示的某个协议类型常值,或者设为0,以选择所给定的family和type组合和系统缺省值。protocol说明IPPROTO_TCPTCP传输协议IPPROTO_UDPUDP传输协议IPPROTO_SCTPSCTP传输协议1.2绑定端口绑定端口指的是将套接字与指定的端口相连。用socket函数建立起一个套接字以后,需要用bind函数在这个套接字上面绑定一个端口。本节将讲解套接字的绑定端口操作。1.2.1绑定端口函数bind函数bind可以将一个端口绑定到一个已经建立的socket上,这个函数的使用方法如下所示。第5页共26页参数列表中,sockfd表示已经建立的socket编号,sockaddr是一个指向sockaddr结构体类型的指针。sockaddr的定义方法如下所示。structsockaddr{unsignedshortintsa_family;charsa_data[14];};这个结构体的成员含义如下所示。sa_family:为调用socket()时的domain参数,即AF_xxxx值。sa_data:最多使用14个字符长度,含有IP地址与端口的信息。如果建立socket时使用的是AF_INET参数,则socketaddr结构体的定义方法如下所示structsocketaddr_in{unsignedshortintsin_family;uint16_tsin_port;structin_addrsin_addr;unsignedcharsin_zero[8];};结构体的成员in_addr也是一个结构体,定义方式如下所示。structin_addr{uint32_ts_addr;};在这些结构体中,成员变量的作用与含义如下所示。sin_family:即为sa_family,为调用socket()时的domain参数。sin_port:使用的端口号。sin_addr.s_addr:IP地址。sin_zero:未使用的字段,填充为0。第6页共26页参数addrlen表示my_addr的长度,可以用sizeof函数来取得。函数可以把指定的IP与端口绑定到已经建立的socket上面。如果绑定成功,则返回0,失败则返回-1。函数可能发生下面的错误,可以用error捕获发生的错误。在使用这个函数前,需要在程序的最前面包含下面的头文件。#includesys/types.h#includesys/socket.h1.2.2bind函数绑定端口实例下面的实例使用了bind函数在一个打开的socket上面绑定IP与端口。绑定的端口是5678,IP为INADDR_ANY,表示本地计算机的默认IP地址。#includesys/types.h#includesys/socket.h#includenetinet/in.h#includearpa/inet.h#includeunistd.h/*包含头文件。*/#definePORT5678/*定义一个表示端口的常量。*/main(){intsockfd,newsockfd,fd;/*定义相关的变量。*/structsockaddr_inaddr;intaddr_len=sizeof(structsockaddr_in);fd_setmyreadfds;charmsgbuffer[256];/*定义一个字符数组存储发送和接收到的信息。*/if((sockfd=socket(AF_INET,SOCK_STREAM,0))0)/*建立一个socket。*/{perror(socket);exit(1);}else/*建立成功。*/{printf(socketcreated.\n);printf(sockedid:%d\n,sockfd);}bzero(&addr,sizeof(addr));/*清空表示地址的结构体变量。*/addr.sin_family=AF_INET;addr.sin_port=htons(PORT);/*设置addr的成员。*/addr.sin_addr.s_addr=htonl(INADDR_ANY);if(bind(sockfd,&addr,sizeof(addr))0)/*bind函数绑定端口。*/{perror(connect);第7页共26页exit(1);}else/*失败的情况。*/{printf(connected.\n);printf(localport:%d\n,PORT);}}程序运行结果如下:socketcreated.sockedid:3connected.localport:56781.3监听与连接所谓监听,指的是socket的端口处于等待状态,如果客户端有连接请求,这个端口会接受这个连接。连接指的是客户端向服务端发送一个通信申请,服务端会响应这个请求。本节将讲述socket的监听与连接操作。1.3.1等待监听函数listen服务器必须等待客户端的连接请求,listen函数用于实现监听等待功能。这个函数的使用方法如下所示。intlisten(ints,intbacklog);在参数列表中,s表示已经建立的socket,backlog表示能同时处理的最大连接请求,如果超过这个数目,客户端将会接收到ECONNREFUSED拒绝连接的错误。需要注意的是,listen并未真正的接受连接,只是设置socket的状态为listen模式,真正接受客户端连接的是accept函数。通常情况下,listen函数会在socket,bind函数之后调用,然后才会调用accept函数。listen函数只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型。如果socket为AF_INET则参数backlog最大值可设至128,即最多可以同时接受128个客户端的请求。如果调用成功,则函数的返回值为0,失败返回-1。函数可能发生如下所示的错误,可以用errno来捕获发生的错误。在使用这个函数前,需要在程序的最前面包含下面的头文件。#includesys/socket.h1.3.2listen函数使用实例本节将讲述一个listen函数使用实例。在程序中,先建立一个socket,然后用bind函数在这个socket上面绑定端口与IP,然后用listen函数设置这个socket进行监听。程序的代码如下所示。第8页共26页#includesys/types.h#includesys/socket.h#includenetinet/in.h#includearpa/inet.h#includeunistd.h/*包含头文件。*/#definePORT5678/*定义一个表示端口号的常量。*/#defineMAX10/*最多的连接客户端数。*/main(){intsockfd,newsockfd,is_connected[MAX],fd;/*定义相关的变量。*/structsockaddr_inaddr;intaddr_len=sizeof(structsockaddr_in);fd_setmyreadfds;charmsgbuffer[256];charmsg[]=Thisisthemessagefromserver.Connected.\n;if((sockfd=socket(AF_INET,SOCK_STREAM,0))0)/*建立一个socket。*/{perror(socket);exit(1);}else/*socket建立成功。*/{printf(socketcreated.\n);printf(sockedid:%d\n,sockfd);}bzero(&addr,sizeof(addr));/*清空addr所在的内存。*/addr.sin_family=AF_INET;/*设置addr的相关信息。*/addr.sin_port=htons(PORT);addr.sin_addr.s_addr=htonl(INADDR_ANY);if(bind(sockfd,&addr,sizeof(addr))0)/*绑定端口。*/{perror(connect);exit(1);}else/*端口绑定成功。*/{printf(connected.\n);printf(localport:%d\n,PORT);}if(listen(sockfd,3)0)/*监听一个端口。*/{perror(listen);/*错误则输出提示。*/exit(1);}else/*输出结果。*/第9页共26页{printf(listenning......\n);}}程序的运行结果如下所示。socketcreated.sockedid:3connected.localport:5678listenning......1.3.3接受连接函数accept服务器处于监听状态时,如果获得客户机的请求会将这个请求放在等待队列中,当系统空闲时将处理客户机的连接请求。接受连接请求的函数是accept,这个函数的使用方法如下所示。intaccept(ints,structsockaddr*addr,int*addrlen);在参数列表中,s表示处于监听状态的socket,addr是一个sockaddr结构体类型的指针,系统会把远程主机的这些信息保存到这个结构体指针上,addrlen表示sockaddr的内存长度,可以用sizeof函数来取得。当accept函数接受一个连接时,会返回一个新的socket编号。以后的数据传输与读取就是通过这个新的socket编号来处理。原来参数中的socket可以继续使用。接受连接以后,远程主机的地址和端口信息将会保存到addr所指的结构体内。如果处理失败,返回值为-1。函数可能产生下面的错误,可以用error来捕获发生的错误。在使用这个函数前,需要在程序中包含下面的头文件。#includesys/types.h#include
本文标题:面向连接的套接字通信-socket编程
链接地址:https://www.777doc.com/doc-6057660 .html