connect()linux网络编程。

#include <sys/types.h>         
#include <sys/socket.h>

三元组(ip地址,协议,端口)就可以标识网络的过程

int connect(int sockfd, const struct sockaddr
*addr, socklen_t addrlen);

 

 

3.1,OSI七层模型与TCP/IP五层模型

 

OSI七层网络模型由下至上呢1顶7交汇,分别吗:

物理层(Physical layer),数据链路层(Data link layer),网络层(Network
layer),传输层(Transport layer),会话层(Session
layer),表示层(Presentation layer),应用层(Application layer)

1.1 应用层,很简单,就是应用程序。这无异层负责确定通信对象,并保证由足够的资源用于通信,这些本还是思念使通信的应用程序干的业务。 
1.2 表示层,负责数据的编码、转化,确保应用层的健康办事。这同样叠,是拿我们见到的界面及亚向前制间互相转化的地方,就是咱的语言与机器语言间的转速。数据的抽、解压,加密、解密都来在这同样层。这同样层根据不同的用目的将数据处理也歧之格式,表现出就是是咱见到底形形色色的公文扩展名。 
1.3 会话层,负责建立、维护、控制会话,区分不同之对话,以及提供单工(Simplex)、半双工(Half
duplex)、全双工(Full duplex)三栽通信模式的劳动。我们平常所理解之NFS,RPC,X
Windows等都干活以这同一重叠。 
1.4 传输层,负责分割、组合数据,实现端到端的逻辑连接。数据在高达三层是完整的,到了立即无异重合开始让剪切,这无异于交汇分割后的多寡为叫做段(Segment)。三次于握手(Three-way
handshake),面向连接(Connection-Oriented)或不面向连接(Connectionless-Oriented)的劳动,流控(Flow
control)等都出在这无异交汇。 
1.5 网络层,负责管理网络地址,定位装置,决定路由于。我们所熟悉的IP地址及路由器即使是做事以即时同层。上层的数据段在马上同样重合为划分,封装后让做包(Packet),包发生零星种植,一种植名叫用户数据包(Data
packets),是上层传下来的用户数据;另一样栽叫路由更新包(Route update
packets),是直接由路由于器发出来的,用来与其它路由器进行路由于信息之置换。 
1.6 数链路层,负责准备物理传输,CRC校验,错误通知,网络拓扑,流控等。我们所熟知的MAC地址及交换机都干活在马上等同层。上层传下来的担保在及时无异于交汇为剪切封装后吃做帧(Frame)。 
1.7 物理层,就是确凿的大体链路,负责用数据因较特流的点子发送、接收,就不多说了。 

 

描述:
The  connect() system call connects the socket referred to by the file
descriptor sockfd to the address specified by addr.  The
addrlen argument specifies the size of addr.  The format of the
address in  addr  is  determined  by  the address space of the socket
sockfd; see socket(2) for further details.

3.2,TCP握手

If  the socket sockfd is of type SOCK_DGRAM then addr
is the address to which datagrams are sent by default, and the only
address from which datagrams are received.  If the socket is of type
SOCK_STREAM or SOCK_SEQPACKET,  this  call attempts to make a
connection to the socket that is bound to the address specified by
addr.

3.2.1 三涂鸦握手建立连接

当TCP/IP协议被,TCP协议提供可靠的连日服务,采用三次于握手建立一个总是。
1,客户端向服务器发送一个SYN J
2,服务器向客户端响应一个SYN K,并对准SYN J进行确认ACK J+1
3,客户端再惦记服务器发一个承认ACK K+1

图片 1
从今图备受可以看,当客户端调用connect时,触发了连要,向服务器发送了SYN
J包,这时connect进入阻塞状态;服务器监听到连年要,即接到SYN
J包,调用accept函数接收请求于客户端发送SYN K ,ACK
J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK
J+1之后,这时connect返回,并针对SYN K进行确认;服务器收到ACK
K+1时常,accept返回,至此三坏握手完毕,连接起。

其三软握手的目的是树立双向的连日,第一浅握手是客户端向劳动器端发出请求 
老二赖握手是劳动器端告诉客户端,第一潮握手是成之,即可以由客户端发送到客户端, 
老三不行握手是客户端告诉服务器端,第二不善握手是成的,即可以从客户端到服务器端 
这般即使保险了客户端以及劳动器端的双向通信,

Generally,  connection-based  protocol sockets may successfully
connect() only once; connectionless protocol sockets may use connect()
multiple times to change their association.  Connectionless sockets may
dissolve  the  association by  connecting to an address with the
sa_family member of sockaddr set to AF_UNSPEC (supported on Linux
since kernel 2.2).

3.2.2 四不成握手释放连接

图片 2

1,某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
2,另一样端接收至FIN
M之后,执行被动关闭,对是FIN进行确认。它的接呢视作文件了符传递给应用进程,因为FIN的吸收意味着应用进程在相应的连日上再为吸收不顶额外数据;
3,一段时间之后,接收到文件截止符的以进程调用close关闭它的socket。这招其的TCP也发送一个FIN
N;
4,接收至之FIN的源发送端TCP对她进行确认。

 

3.3,socket编程

http://www.cnblogs.com/goodcandle/archive/2005/12/10/socket.html

事先由劳动器端说从。服务器端先初始化Socket,然后跟端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时候如出只客户端初始化一个Socket,然后连服务器(connect),如果连接成功,这时客户端和服务器端的连接就起了。客户端发送数据请求,服务器端接收请求并处理要,然后将回应数据发送给客户端,客户端读取数据,最后关闭连接,一涂鸦相结束。

返回值:
If the connection or binding succeeds, zero is returned.  On error, -1
is returned, and errno is set appropriately.

3.3.1 AF_INET TCP传输最简单易行版本

图片 3

 

tcp_client.c

 

[cpp] view
plain copy

 

  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8. #include <netinet/in.h>  
  9.   
  10. #define PORT 6666  
  11. #define BUFF_SIZE 1024  
  12. #define MAXLEN 4096  
  13.   
  14. main(int argc, char** argv)  
  15. {  
  16.     if(argc!=2){  
  17.         printf(“usage: ./client <ipaddress>\n”);  
  18.         exit(0);  
  19.     }  
  20.       
  21.     char sendline[4096];  
  22.       
  23.     //socket()建立socket  
  24.     int sockfd = socket(AF_INET,SOCK_STREAM,0);  
  25.   
  26.     //要连接的服务器地址  
  27.     struct sockaddr_in sliaddr;  
  28.     sliaddr.sin_family = AF_INET;  
  29.     sliaddr.sin_port = htons(PORT);  
  30.     inet_pton(AF_INET, argv[1], &sliaddr.sin_addr);  
  31.   
  32.     //connect()发送请求(ip=argv[1],protocal=TCP,port=6666)  
  33.     connect(sockfd, (struct sockaddr*)&sliaddr, sizeof(sliaddr));  
  34.   
  35.     //recv sth  
  36.     recv_len = recv(sockfd, buff, sizeof(buff), 0);  
  37.     buff[recv_len] = ‘\0’;  
  38.     printf(” %s “, buff);  
  39.    
  40.     //interactive  
  41.     while (1)  
  42.     {  
  43.         printf(“Enter string to send: “);  
  44.         scanf(“%s”, buff);  
  45.         if (!strcmp(buff, “quit”))  
  46.             break;  
  47.            
  48.         send_len = send(sockfd, buff, strlen(buff), 0);  
  49.         recv_len = recv(sockfd, buff, BUFF_SIZE, 0);  
  50.         buff[recv_len] = ‘\0’;  
  51.         printf(”    received: %s \n”, buff);  
  52.     }  
  53.   
  54.     //close()关闭连接  
  55.     close(sockfd);  
  56. }  

 

tcp_server.c

 

[cpp] view
plain copy

 

  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8. #include <netinet/in.h>  
  9.   
  10. #define PORT 6666  
  11. #define WAIT_QUEUE_LEN 5  
  12. #define BUFF_SIZE 1024  
  13. #define WELCOME “Welcome to my server ^_^!\n”  
  14.   
  15. main()  
  16. {  
  17.     int connfd;  
  18.     char buff[MAXLEN];  
  19.     int len;  
  20.   
  21.     //socket() 建立socket,其中SOCK_STREAM表示tcp连接  
  22.     int sockfd = socket(AF_INET,SOCK_STREAM,0);  
  23.       
  24.     struct sockaddr_in servaddr;  
  25.     servaddr.sin_family = AF_INET;  
  26.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  27.     servaddr.sin_port = htons(PORT);  
  28.       
  29.     //bind()绑定一个socket(ip=all,protocal=TCP,port=6666)  
  30.     bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr));  
  31.   
  32.     //listen()监听  
  33.     listen(sockfd, WAIT_QUEUE_LEN);  
  34.   
  35.     //accept() & close()  
  36.     printf(“======waiting for client’s request======\n”);  
  37.     while(1){  
  38.         c_addrlen = sizeof(struct sockaddr_in);  
  39.         connfd = accept(serverfd, (struct sockaddr *)&caddr, &c_addrlen);  
  40.         printf(“client: ip=%s,port=%s\n”, cliaddr.sin_addr.s_addr,cliaddr.sin_port);  
  41.           
  42.         //send a welcome  
  43.         send(connfd, WELCOME, strlen(WELCOME), 0);  
  44.        
  45.         //阻塞模式下recv==0表示客户端都断开连接  
  46.         while ((len = recv(connfd, buff, BUFF_SIZE, 0)) > 0)  
  47.         {  
  48.             buff[len] = ‘\0’;  
  49.             printf(“recv msg is : %s \n”, buff);  
  50.             send(connfd, buff, len, 0);  
  51.         }  
  52.           
  53.         close(connfd);  
  54.     }  
  55.   
  56.     //close()关闭连接  
  57.     close(sockfd);  
  58. }  

堵塞与非阻塞recv返回值没有分别,都是
<0 出错
=0 连接关闭
>0 接收及数大小,

 

makefile

 

[plain] view
plain copy

 

  1. .PHONY : main  
  2. main : server client  
  3. server : server.o  
  4.         gcc -g -o server server.o   
  5. client : client.o  
  6.         gcc -g -o client client.o   
  7. server.o : server.c  
  8.         gcc -g -c server.c  
  9. client.o : client.c  
  10.         gcc -g -c client.c  
  11. clean :   
  12.         rm -rf *.o  
  13. ser :  
  14.         ./server  
  15. cli :  
  16.         ./client  

 

 

3.3.2 加入返回值检查以及IP地址

tcp_client.c

 

[cpp] view
plain copy

 

  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8. #include <netinet/in.h>  
  9.   
  10. #define MAXLEN 4096  
  11.   
  12. main(int argc, char** argv)  
  13. {  
  14.     if(argc!=2){  
  15.         printf(“usage: ./client <ipaddress>\n”);  
  16.         exit(0);  
  17.     }  
  18.       
  19.     char sendline[4096];  
  20.       
  21.     //socket()建立socket  
  22.     int sockfd;  
  23.     if((sockfd=socket(AF_INET,SOCK_STREAM,0)) ==-1){  
  24.         printf(“create socket error: %s(errno: %d)\n”, strerror(errno),errno);  
  25.     }  
  26.   
  27.     struct sockaddr_in cliaddr;  
  28.     cliaddr.sin_family = AF_INET;  
  29.     cliaddr.sin_port = htons(6666);  
  30.     if(inet_pton(AF_INET, argv[1], &cliaddr.sin_addr)==-1){  
  31.         printf(“inet_pton error for %s\n”,argv[1]);  
  32.         exit(0);  
  33.     }  
  34.   
  35.     //connect()发送请求(ip=argv[1],protocal=TCP,port=6666)  
  36.     if(connect(sockfd, (struct sockaddr*)&cliaddr, sizeof(cliaddr))==-1){  
  37.         printf(“connect error: %s(errno: %d)\n”,strerror(errno),errno);  
  38.         exit(0);  
  39.     }  
  40.   
  41.     printf(“send msg to server: \n”);  
  42.     fgets(sendline, 4096, stdin);  
  43.   
  44.     //send()发送数据  
  45.     if(send(sockfd, sendline, strlen(sendline), 0)==-1){  
  46.         printf(“send msg error: %s(errno: %d)\n”, strerror(errno), errno);  
  47.         exit(0);  
  48.     }  
  49.   
  50.     //close()关闭连接  
  51.     close(sockfd);  
  52. }  

tcp_server.c

 

 

[cpp] view
plain copy

 

  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8. #include <netinet/in.h>  
  9.   
  10. #define MAXLEN 4096  
  11.   
  12. main()  
  13. {  
  14.     int connfd;  
  15.     char buff[MAXLEN];  
  16.     int n;  
  17.   
  18.     //socket()建立socket  
  19.     int sockfd;  
  20.     if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){  
  21.         printf(“create socket error: %s(errno:%d)\n”,strerror(errno),errno);  
  22.         exit(0);  
  23.     }  
  24.       
  25.     struct sockaddr_in servaddr;  
  26.     servaddr.sin_family = AF_INET;  
  27.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  28.     servaddr.sin_port = htons(6666);  
  29.       
  30.     //bind()绑定一个socket(ip=all,protocal=TCP,port=6666)  
  31.     if(bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr))==-1){  
  32.         printf(“bind socket error: %s(errno: %d)\n”,strerror(errno),errno);  
  33.         exit(0);  
  34.     }  
  35.   
  36.     //listen()监听  
  37.     if(listen(sockfd,10)==-1){  
  38.         printf(“listen socket error: %s(errno: %d)\n”,strerror(errno),errno);  
  39.         exit(0);  
  40.     }  
  41.   
  42.     //accept() & close()  
  43.     printf(“======waiting for client’s request======\n”);  
  44.     while(1){  
  45.         if((connfd=accept(sockfd, (struct sockaddr *)NULL,NULL))==-1){  
  46.             printf(“accept socket error: %s(errno: %d)”,strerror(errno),errno);  
  47.             continue;  
  48.         }  
  49.         struct sockaddr_in serv, guest;  
  50.         char serv_ip[20];  
  51.         char guest_ip[20];  
  52.         int serv_len = sizeof(serv);  
  53.         int guest_len = sizeof(guest);  
  54.         getsockname(connfd, (struct sockaddr *)&serv, &serv_len);  
  55.         getpeername(connfd, (struct sockaddr *)&guest, &guest_len);  
  56.         inet_ntop(AF_INET, &serv.sin_addr, serv_ip, sizeof(serv_ip));  
  57.         inet_ntop(AF_INET, &guest.sin_addr, guest_ip, sizeof(guest_ip));  
  58.         printf(“host %s:%d guest %s:%d\n”, serv_ip, ntohs(serv.sin_port), guest_ip, ntohs(guest.sin_port));  
  59.         n = recv(connfd, buff, MAXLEN,0);  
  60.         buff[n] = ‘\0’;  
  61.         printf(“recv msg from client: %s\n”, buff);  
  62.         close(connfd);  
  63.     }  
  64.   
  65.     //close()关闭连接  
  66.     close(sockfd);  
  67. }  

 

connect函数的职能是瓜熟蒂落一个发出连日协议的连接过程,对于TCP来说就是是很三蹩脚握手过程。

3.3.3 AF_INET UDP传输最简便版本

图片 4

udp_client.c

 

[cpp] view
plain copy

 

  1. /** 
  2. *   @file: udpclient.c 
  3. *   @brief: A simple Udp server 
  4. *   @author: ToakMa <mchgloak1120@163.com> 
  5. *   @date:  2014/10/09 
  6. */  
  7.    
  8. #include <stdio.h>  
  9. #include <stdlib.h>  
  10. #include <string.h>  
  11. #include <strings.h>  
  12. #include <sys/types.h>  
  13. #include <sys/socket.h>  
  14. #include <netinet/in.h>  
  15. #include <arpa/inet.h>  
  16.    
  17. #define BUFF_SIZE 1024  
  18. #define PORT     9988  
  19.    
  20. int main(int argc, char *argv[])  
  21. {  
  22.     int sockfd;  
  23.     struct sockaddr_in remote_addr;  
  24.     int len;  
  25.     char buff[BUFF_SIZE];  
  26.    
  27.     //1. create a socket  
  28.     sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
  29.     if (-1 == sockfd)  
  30.     {  
  31.         perror(“udp client socket: “);  
  32.         return -1;  
  33.     }  
  34.        
  35.     //2. prepare ip and port  
  36.     memset(&remote_addr, 0, sizeof(remote_addr));  
  37.     remote_addr.sin_family = AF_INET;  
  38.     remote_addr.sin_port   = htons(PORT);  
  39.     remote_addr.sin_addr.s_addr = inet_addr(argv[1]);  
  40.     bzero(&(remote_addr.sin_zero), 8);  
  41.        
  42.     //3. sendto  
  43.     strcpy(buff, “this a test\n”);  
  44.     printf(“sending : %s\n”, buff);  
  45.     len = sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&remote_addr, sizeof(remote_addr));  
  46.     if (len < 0)  
  47.     {  
  48.         perror(“udp client sendto :”);  
  49.         return -1;  
  50.     }  
  51.        
  52.     //4. close  
  53.     close(sockfd);  
  54.    
  55.     return 0;  
  56. }  

 

 

udp_server.c

 

[cpp] view
plain copy

 

  1. /** 
  2. *   @file: udpserver.c 
  3. *   @brief: A simple Udp server 
  4. *   @author: ToakMa <mchgloak1120@163.com> 
  5. *   @date:  2014/10/09 
  6. */  
  7. #include <stdlib.h>  
  8. #include <stdio.h>  
  9. #include <string.h>  
  10. #include <strings.h>  
  11. #include <sys/types.h>  
  12. #include <sys/socket.h>  
  13. #include <netinet/in.h>  
  14. #include <arpa/inet.h>  
  15.    
  16. #define PORT 9988  
  17. #define BUFF_SIZE 1024  
  18.    
  19. int main(int argc, char *argv[])  
  20. {  
  21.     int sockfd;  
  22.     int sin_len;  
  23.     struct sockaddr_in saddr;  
  24.     struct sockaddr_in remote_addr;  
  25.     char buff[BUFF_SIZE];     
  26.     int res, len;  
  27.    
  28.     //1. create socket  
  29.     sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
  30.     if (-1 == sockfd)  
  31.     {  
  32.         perror(“Udp server socket: “);  
  33.         return -1;  
  34.     }  
  35.     printf(“Udp server socket create succ!\n”);  
  36.    
  37.     //2. prepare IP and port  
  38.     memset(&saddr, 0, sizeof(saddr));  
  39.     saddr.sin_family = AF_INET;  
  40.     saddr.sin_port   = htons(PORT);  
  41.     saddr.sin_addr.s_addr = INADDR_ANY;  
  42.     bzero(saddr.sin_zero, 8);  
  43.    
  44.     //3. bind  
  45.     res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));  
  46.     if (-1 == res)  
  47.     {  
  48.         perror(“udp server bind: “);  
  49.         return -1;  
  50.     }  
  51.        
  52.     //4. recvfrom  
  53.     printf(“Wait for a packet …\n”);  
  54.     sin_len = sizeof(struct sockaddr_in);  
  55.     len = recvfrom(sockfd, buff, BUFF_SIZE, 0, (struct sockaddr *)&remote_addr, &sin_len);  
  56.     if (-1 == len)  
  57.     {  
  58.         perror(“udp server recvform: “);  
  59.         return -1;  
  60.     }  
  61.     buff[len] = ‘\0’;  
  62.    
  63.     printf(“Recived packet from %s, contents is: %s \n”, \  
  64.         inet_ntoa(remote_addr.sin_addr), buff);  
  65.    
  66.    
  67.     //5. close  
  68.     close(sockfd);  
  69.    
  70.     return 0;  
  71. }  

 

以知道connect函数,我们用对connect函数的职能进行介绍。connect函数的功效可为此平等词话来概括,就是就面向连接的说道的连年过程,它是主动连接的,面向连接的磋商,在成立连接的时刻总会发出一样正值预先发送数据,那么谁调用了connect谁就是是预先发送数据的平等正。如此清楚connect三独参数是好了,我必需指定数量发送的地址,同时为必不可少指定数量由哪发送,这刚好是connect的前少独参数,而第三个参数是啊第二只参数服务之。

3.3.4 AF_INET UNIX本地传输最简单易行版本

unix_client.c

 

[cpp] view
plain copy

 

  1. #include <sys/types.h>  
  2. #include <sys/socket.h>  
  3. #include <stdio.h>  
  4. #include <sys/un.h>  
  5. #include <unistd.h>  
  6. #include <errno.h>   
  7.   
  8. int main()  
  9. {  
  10.       
  11.     int result;  
  12.     char ch = ‘A’;  
  13.   
  14.     //创建socket  
  15.     int sockfd;  
  16.     if((sockfd = socket(AF_UNIX,SOCK_STREAM,0) == -1){  
  17.         printf(“create socket error: %s(errno: %d)\n”, strerror(errno),errno);  
  18.     }  
  19.   
  20.     struct sockaddr_un address;  
  21.     address.sun_family = AF_UNIX;  
  22.     strcpy(address.sun_path,”server_socket”);  
  23.     int len = sizeof(address);  
  24.   
  25.     //connect()  
  26.     int result;  
  27.     if((result = connect(socket,(struct sockaddr*)&address,len)==-1){  
  28.         printf(“connect error: %s(errno: %d)\n”,strerror(errno),errno);    
  29.         exit(0);    
  30.     }  
  31.   
  32.     //read & write  
  33.     write(sockfd,&ch,1);  
  34.     read(sockfd,&ch,1);  
  35.     printf(“char from server = %c\n”,ch);  
  36.   
  37.     //close()  
  38.     close(sockfd);  
  39.     exit(0);  
  40. }  

unix_server.c

 

 

[cpp] view
plain copy

 

  1. #include <sys/types.h>  
  2. #include <sys/socket.h>  
  3. #include <stdio.h>  
  4. #include <sys/un.h>  
  5. #include <unistd.h>  
  6. #include <errno.h>   
  7.   
  8. int main()  
  9. {  
  10.     int server_len,client_len;  
  11.     struct socket_un server_address;  
  12.     struct socket_un client_address;  
  13.   
  14.     //删除以前套接字  
  15.     unlink(“server_socket”);  
  16.   
  17.     //socket  
  18.     int server_sockfd = socket(AF_UNIX,SOCK_STREAM,0);  
  19.   
  20.     server_address.sun_family = AF_UNIX;  
  21.     strcpy(server_address.sun_path,”server_socket”);  
  22.     server_len = sizeof(server_address);  
  23.   
  24.     //bind()  
  25.     bind(server_sockfd,(struct sockaddr*)&server_address,server_len);  
  26.   
  27.     //listen()  
  28.     listen(server_sockfd,5);  
  29.     while(1){  
  30.         char ch;  
  31.         printf(“server waiting\n”);  
  32.         client_len = sizeof(client_address);  
  33.         client_sockfd = accept(server_sockfd,(struct sockaddr*)&client_address,&client_len);  
  34.   
  35.         //read & write  
  36.         read(client_sockfd,&ch,1);  
  37.         ch++;  
  38.         write(client_sockfd,&ch,1);  
  39.         close(client_sockfd);  
  40.     }  
  41. }  

 

 

3.4 网络编程函数

http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html

http://blog.csdn.net/simba888888/article/details/9012521

Unix/Linux基本哲学之一就是是“一切均文件”,都足以用“打开open –>
读写write/read –> 关闭close”

 

[plain] view
plain copy

 

  1. #include<sys/types.h>  
  2. #include<sys/socket.h>  

 

 

3.4.1 函数socket

缔造套接字:socket函数对应于普通文书之开辟操作。普通文书的开拓操作返回一个文本讲述字,而socket()用于创造一个socket描述吻合(socket
descriptor),它唯一标识一个socket。

[plain] view
plain copy

 

  1. 函数原型:  
  2. int socket(int domain, int type, int protocol);  
  3. 参数说明:  
  4. domain:即协议域。常用的协议族有,AF_INET(ipv4)、AF_INET6(ipv6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。  
  5. type:指定socket类型。常用的socket类型有,SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。  
  6. protocol:指定协议。常用的情商来,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等。  
  7. int:返回值为-1代表来错  

在意:并无是上面的type和protocol可以自由组合的,如SOCK_STREAM不得以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。

 

sockfd,指定数量发送的套接字,解决从哪发送的问题。内核需要保护大量IO通道,所以用户必需通过此参数告诉本从哪个IO通道,此处就于哪个socket接口中发送数据。sockfd是先前socket()返回的值。

3.4.2 函数bind

取名套接字:bind()函数把一个地址族中之一定地方与给socket。例如对应AF_INET、AF_INET6纵是拿一个ipv4或ipv6地址及端口号组合赋给socket。

 

[plain] view
plain copy

 

  1. 函数原型:  
  2. int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);  
  3. 参数说明:  
  4. sockfd:是出于socket()调用返回的套接口文件讲述吻合。  
  5. addr:传入数据结构sockaddr的指针,包括(IP,protocol,port)需要更换为通用地址类型struct sockaddr*  
  6. addrlen:以安成sizeof(struct sockaddr)  
  7. int:返回值,-1象征有错  

 

[plain] view
plain copy

 

  1. ipv4地址结构【AF_INET】:  
  2. struct sockaddr_in {  
  3.     sa_family_t    sin_family; /* address family: AF_INET */  
  4.     in_port_t      sin_port;   /* port in network byte order */  
  5.     struct in_addr sin_addr;   /* internet address */  
  6. };  
  7.   
  8. /* Internet address. */  
  9. struct in_addr {  
  10.     uint32_t       s_addr;     /* address in network byte order */  
  11. };  

ipv6地址结构【AF_INET6】:

[plain] view
plain copy

 

  1. struct sockaddr_in6 {   
  2.     sa_family_t     sin6_family;   /* AF_INET6 */   
  3.     in_port_t       sin6_port;     /* port number */   
  4.     uint32_t        sin6_flowinfo; /* IPv6 flow information */   
  5.     struct in6_addr sin6_addr;     /* IPv6 address */   
  6.     uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */   
  7. };  
  8.   
  9. struct in6_addr {   
  10.     unsigned char   s6_addr[16];   /* IPv6 address */   
  11. };  

Unix域地址结构【AF_UNIX】:

[plain] view
plain copy

 

  1. #define UNIX_PATH_MAX    108  
  2.   
  3. struct sockaddr_un {   
  4.     sa_family_t sun_family;               /* AF_UNIX */   
  5.     char        sun_path[UNIX_PATH_MAX];  /* pathname */ 使用strcpy(address.sun_path,”server_socket”)   
  6. };  

常备服务器在启动之上还见面绑定一个斐然的地点(如ip地址+端口号),用于供服务,客户就是可以通过其来连续服务器;所以服务器端在listen之前见面调用bind()。

一经客户端就无须指定,有网自动分配一个端口号和自家之ip地址做,在connect()时由系统随机大成一个。由于客户端不需要固定的捧口号,因此不用调用bind(),客户端的端口号由基础自动分配。注意,客户端不是无允调用bind(),只是没必要调用
bind()固定一个端口号,服务器也未是要调用bind(),但如服务器不调用bind(),内核会自动为服务器分配监听端口,每次启动服务器时端口号都无平等,客户端要连服务器就会赶上麻烦。

 

针对server端的addr的初始化如下所示:

 

[cpp] view
plain copy

 

  1. memset(&servaddr, 0, sizeof(servaddr));  
  2. servaddr.sin_family = AF_INET;  
  3. servaddr.sin_port = htons(5188);  
  4. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  

第一将全部结构体清零(也得就此bzero函数),然后设置地点类型为AF_INET,网络地址为INADDR_ANY,这个大表示当地的任意IP地址,因为服务器可能来多独网卡,每个网卡也说不定绑定多个IP地址,这样设置可以在有着的IP地址及监听,直到和有客户端起了连年时才确定下到底用谁IP地址,端口号也5188。

 

 

3.4.3 函数listen

开创套接字队列

[plain] view
plain copy

 

  1. 函数原型:  
  2. int listen(int sockfd, int backlog);  
  3. 参数说明:  
  4. sockfd:即为使监听的socket描述字  
  5. backlog:相应socket可以排队的极其深连接个数  

仲独参数是入队列中允许的连的个数。进入的连天要在运用系统调用accept()应答之前如果当上队列中待。这个价是排中最为多得拥有的请求的个数。大多数系的缺省设置也20。你得设置为5或10。当出错时,listen()将会晤回去-1价值。

以此函数对于backlog的解释《unix网络编程》P85是说就到位连接队列(ESTABLISHED)和莫得连接队列(SYN_RCVD)之与(即等待连接数如不连接数)。服务器调用的accept()返回并受之连续,如果生雅量的客户端发起连接而服务器来不及处理,尚未accept的客户端就高居连接等状态,listen()声明sockfd处于监听状态,并且最多允许生backlog个客户端处于连接等状态,如果接到到还多之连接要虽大意。在微机早期由于网络连接的处理速度很缓慢,几单冒出的伸手虽可能导致系统处理不回复而引发错误,现在夫数字的含义都很小了,现在软硬件性能几乎会保证这行列不可能满。连接的状态变为ESTABLISHED之后(实际是接连由由大体上连连队列转移至了成就握手的到位队列)才代表可以被accpet()处理。

addr,指定数量发送的目的地,也就是是劳务器端的地点。这里服务器是本着connect说的,因为connect是主动连接的一模一样正值调用的,所以相应的如果存在一个吃连的均等正,被动连接的相同在用调用listen以接受connect的连接要,如此低沉连接的同样着虽是服务器了。

3.4.4 函数accept

纳连接

[plain] view
plain copy

 

  1. 函数原型:  
  2. int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);  
  3. 参数说明:  
  4. sockfd:是出于socket()调用返回的套接口文件讲述称。  
  5. addr:传出连接客户之sockaddr指针,包括(IP,protocol,port)  
  6. addrlen:传入指定客户结构addr的长度,返回时该值传出为连客户地址addr的骨子里尺寸  
  7. int:返回值,-1象征出错  

调用accept()之后,将会晤回来一个新的套接口文件讲述符来处理此单个的连日。这样,对于与一个总是来说,你就是有矣区区个文本讲述吻合。原先的一个文本讲述符正在监听而指定的端口,新的文本讲述吻合可以就此来调用send()和recv()。

可以经过对法接字文件讲述符设置O_NONBLOCK来转该是否封堵:

 

[cpp] view
plain copy

 

  1. int flags = fcntl(socket, F_GETFL,0);  
  2. fcntl(socket, F_SETFL, O_NONBLOCK| flags);  

 

 

 

3.4.5 函数connect

[plain] view
plain copy

 

  1. 函数原型:  
  2. int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);  

客户端连接服务器,addr为流传参数,表示目的服务器的(ip,protocal,port)。

 

addrlen,指定addr结构体的尺寸。我们了解系统遭到设有大气底地方结构,但socket接口只是通过一个合之构造来指定参数类型,所以用指定一个尺寸,以使基本在进行参数复制的时来只有个度。

3.4.6 函数read与write

read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()

 

[plain] view
plain copy

 

  1. #include <unistd.h>  
  2. ssize_t read(int fd, void *buf, size_t count);  
  3. ssize_t write(int fd, const void *buf, size_t count);  
  4.   
  5. #include <sys/types.h>  
  6. #include <sys/socket.h>  
  7. ssize_t send(int sockfd, const void *buf, size_t len, int flags);  
  8. ssize_t recv(int sockfd, void *buf, size_t len, int flags);  
  9.   
  10. ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,  
  11.                const struct sockaddr *dest_addr, socklen_t addrlen);  
  12. ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,  
  13.                struct sockaddr *src_addr, socklen_t *addrlen);  
  14.   
  15. ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);  
  16. ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);  

3.4.7 函数close

 

[plain] view
plain copy

 

  1. 函数原型:  
  2. int close(int fd);  

顾:close操作只是要相应socket描述字的援计数-1,只有当引用计数为0的时刻,才见面触发TCP客户端向服务器发送终止连接要。

3.4.8 函数getsockname

函数返回跟法接口关联的本土协议地址。

 

[plain] view
plain copy

 

  1. 函数原型:  
  2. int getsockname(int sockfd, struct sockaddr * localaddr, socken_t * addrlen);  

 

3.4.9 函数getpeername

函数返回跟法接口关联的远程协议地址。

 

[plain] view
plain copy

 

  1. 函数原型:  
  2. int getpeername(int sockfd,struct sockaddr* peeraddr,int* addrlen);  
  3. 参数说明:  
  4. sockfd:是由于socket()调用返回的套接口文件讲述吻合。  
  5. peeraddr:传出数据结构sockaddr的指针,包括(IP,protocol,port)  
  6. addrlen:传出结构大小的指针  
  7. int:返回值,-1象征来错  

 

3.5 网络配节序与主机字节序转换

以主机字节序转换为网络配节序(避免多头小端问题)

#include <netinet/in.h>

3.5.1 函数htonl

 

[plain] view
plain copy

 

  1. uint32_t htonl(uint32_t hostlong);  

 

3.5.2 函数htons

 

 

[plain] view
plain copy

 

  1. uint16_t htons(uint16_t hostshort);  

 

3.5.3 函数ntohl

 

[plain] view
plain copy

 

  1. uint32_t ntohl(uint32_t netlong);  

 

 

3.5.4 函数ntohs

[plain] view
plain copy

 

  1. uint16_t ntohs(uint16_t netshort);  

 

3.6 IP地址与主机字节序转换

 

3.6.1 函数inet_pton

[以“点分十进制” -> “整数”]

 

[plain] view
plain copy

 

  1. 函数原型:  
  2. int inet_pton(int af, const char *src, void *dst);  
  3. 参数说明:  
  4. af:地址族,AF_INET为ipv4地址,AF_INET6为ipv6地址  
  5. src:为ip地址(ipv4例如1.1.1.1)  
  6. dst:函数将拖欠地方转换为in_addr的结构体,并复制在*dst中  
  7. int:返回值:如果函数出错将回来一个负值,并拿errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将回到回0。  

 

3.6.2 函数inet_ntop

 

[将“整数” -> “点分十进制”]

[plain] view
plain copy

 

  1. 函数原型:  
  2. const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);  

 

3.7 主机数据库函数

3.7.1 函数gethostname

其回到(本地)计算机的讳,存储于hostname中,大小为size

 

[plain] view
plain copy

 

  1. 函数原型:  
  2. int gethostname(char*hostname,size_tsize);  
  3. 参数说明:  
  4. int:返回值gethostname将赶回回0。如果失败,它用回到-1。   

3.7.2 函数gethostbyname

冲域名还是主机名获取信息

 

[cpp] view
plain copy

 

  1. 函数原型:  
  2. struct hostent *gethostbyname(const char *name);  
  3. 参数说明:  
  4. name:主机名,如”www.baidu.com”  
  5. hostend:返回值。如果函数调用失败,将赶回NULL。  

 

hostend的构造如下:

 

[cpp] view
plain copy

 

  1. struct hostent   
  2. {  
  3.   char  *h_name;            //表示的凡主机的正规名,例如www.google.com的正式名其实是www.l.google.com  
  4.   char  **h_aliases;        //表示的是主机的别名  
  5.   int   h_addrtype;         //IP地址之花色  
  6.   int   h_length;           //IP地址的尺寸  
  7.   char  **h_addr_list;      //主机的ip地址,注意及时是为网字节顺序保存的一个价,用inet_ntop恢复  
  8. };  

 

以身作则代码:

 

[cpp] view
plain copy

 

  1. #include <netdb.h>  
  2. #include <sys/socket.h>  
  3. #include <stdio.h>  
  4. #include <unistd.h>  
  5.   
  6. int main(int argc, char **argv)  
  7. {  
  8.     char *host,**names;  
  9.     struct hostent *hostinfo;  
  10.     cha str[32];  
  11.     /* 取得命令后首先单参数,即如分析的域名还是主机名 */  
  12.     if(argc==1){  
  13.         char myname[256];  
  14.         gethostname(myname,255);  
  15.         host=myname;  
  16.     }  
  17.     else{  
  18.         host=argv[1];  
  19.     }  
  20.     /* 调用gethostbyname()。调用结果尚且是hostinfo中 */  
  21.     if( (hostinfo = gethostbyname(host) ) == NULL )  
  22.     {  
  23.         printf(“gethostbyname error for host:%s/n”, host);  
  24.         exit(1); /* 如果调用gethostbyname发生误,返回1 */  
  25.     }  
  26.     /* 将主机的科班名打出来 */  
  27.     printf(“official hostname:%s/n”,hostinfo->h_name);  
  28.     /* 主机可能有多单号,将有着变更称作分别从出去 */  
  29.     for(names = hostinfo->h_aliases; *names != NULL; names++)  
  30.         printf(” alias:%s/n”,*names);  
  31.     /* 根据地址类型,将地方打出去 */  
  32.     switch(hostinfo->h_addrtype)  
  33.     {  
  34.     case AF_INET:  
  35.     case AF_INET6:  
  36.         names=hostinfo->h_addr_list;  
  37.         /* 将刚得到的装有地方都自出去。其中调用了inet_ntop()函数 */  
  38.         for(;*names!=NULL;names++)  
  39.             printf(” address:%s/n”, inet_ntop(hostinfo->h_addrtype, *names, str, sizeof(str)));  
  40.         break;  
  41.     default:  
  42.         printf(“unknown address type/n”);  
  43.         break;  
  44.     }  
  45.     exit(0);  
  46. }   

 

3.7.3 函数gethostbyaddr

基于ip地址(网络配节序)获取信息

 

[cpp] view
plain copy

 

  1. 函数原型:  
  2. struct hostent *gethostbyaddr(const char *name,int len,int type)  
  3. 参数说明:  
  4. name:ip地址,例如: inet_addr(“192.168.4.111”)  
  5. len:  
  6. type:  
  7. hostend:返回值。如果函数调用失败,将回NULL。  

 

 

3.7.4 函数getservbyname

 

用以因加的讳来探寻相应的服务器,返回对应于给定服务名及协议名的连锁服务信息

 

[cpp] view
plain copy

 

  1. 函数原型:  
  2. struct servernt *gerservbyname(const char *servname,const char *protoname)  
  3. 参数说明:  
  4. servname:例如smtp  
  5. protoname:例如tcp  

 

servent结构如下:

 

[cpp] view
plain copy

 

  1. struct servent{  
  2.     char *s_name;    /*劳之规范名字*/  
  3.     char **s_aliases;/*变更名列表*/  
  4.     int s_port;      /*服务的端口号*/  
  5.     char *s_proto;   /*劳务之情商,如tcp或udp*/  
  6. }  

 

3.7.5 函数getservbyport

回来跟给定服务名对应之涵盖名字以及服务号信息的servent结构指针(注意参数port的价值必须是网络配节序类型的,所以于动用的时段用运用函数htons(port)来进行更换)。

 

[cpp] view
plain copy

 

  1. 函数原型:  
  2. struct servent *getservbyport(int port,const char *proroname);  
  3. 函数示例:  
  4. sptr=getservbyport(htons(53),”udp”);  

演示代码:

 

[cpp] view
plain copy

 

  1. #赢得任意已解主机的日期和时空  
  2. #include <netdb.h>  
  3. #include <sys/socket.h>  
  4. #include <netinet/in.h>  
  5. #include <stdio.h>  
  6. #include <unistd.h>  
  7.   
  8. int main(int argc, char **argv)  
  9. {  
  10.     char *host;  
  11.     struct hostent * hostinfo;  
  12.     struct servent * servinfo;  
  13.     /* 取得命令后率先独参数,即要分析的域名还是主机名 */  
  14.     if(argc==1){  
  15.         host=”localhost”;  
  16.     }  
  17.     else{  
  18.         host=argv[1];  
  19.     }  
  20.     /* 调用gethostbyname()。调用结果都有hostinfo中 */  
  21.     if( (hostinfo = gethostbyname(host) ) == NULL )  
  22.     {  
  23.         printf(“gethostbyname error for host:%s/n”, host);  
  24.         exit(1); /* 如果调用gethostbyname发生错误,返回1 */  
  25.     }  
  26.     if ( (servinfo = getservbyname(“daytime”,”tcp”)) );  
  27.     {  
  28.         printf(“no daytime service/n”);  
  29.         exit(1); /* 如果调用getservbyname发生误,返回1 */  
  30.     }  
  31.     /* 将daytime的端口打印出来*/  
  32.     printf(“daytime port is %d/n”,ntohs(servinfo -> s_port));  
  33.   
  34.     int sockfd = socket(AF_INET, SOCK_STREAM,0);  
  35.     struct sockaddr_in address;  
  36.     address.sin_family = AF_INET;  
  37.     address.sin_port = servinfo -> s_port;  
  38.     address.sin_addr= *(struct in_addr*)*hostinfo->h_addr_list;  
  39.     int len = sizeof(address);  
  40.   
  41.     int result;  
  42.     if((result = connect(socket,(struct sockaddr*)&address,len))==-1){  
  43.         printf(“connect error: %s(errno: %d)\n”,strerror(errno),errno);    
  44.         exit(0);   
  45.     }  
  46.   
  47.     char buffer[128];  
  48.     result = read(sockfd,buffer,sizeof(buffer));  
  49.     buffer[result]=’\0′;  
  50.     printf(“read %d bytes: %s”,result,buffer);  
  51.   
  52.     close(sockfd);  
  53.     exit(0);  
  54. }   

3.5 多客户编程

http://blog.csdn.net/simba888888/article/details/9034407

3.5.1 阻塞与非阻塞

(1)阻塞block
   
所谓阻塞方式block,顾名思义,就是过程或线程执行到这些函数时务必待某个事件之发出,如果事件没发生,进程要线程就为死(进程Sleep),函数不克立时回。
    例如socket编程中connect、accept、recv、recvfrom这样的死程序。
   
再设大部分的函数调用、语句执行,严格来说,他们还是坐堵塞方式实行之。
(2)非阻塞non-block
   
所谓非阻塞方式non-block,就是经过要线程执行之函数时不要非要等待事件之发,一旦推行一定回来,以回到回值的不等来反映函数的尽情况,如果事件闹则跟死方式一样,若事件没发生则回一个代码来报告事件非发生,而经过或线程继续执行,所以效率比高。
 
 非阻塞I/O有一个欠缺,如果拥有装备都一直尚未数据到,调用者需要频繁查询做无用功,如果打断在那边,操作系统可以调度别的进程执行,就无会见做无用功了。?????

3.5.2 函数select

 

[cpp] view
plain copy

 

  1. 函数原型:  
  2. int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);    
  3. 参数说明:  
  4. nfds:为文件讲述符集合中的无比特别值+1,避免函数检查fd_set的所有1024位  
  5. readfds:被监督是否足以读   
  6. writefds:被监督是否好写   
  7. exceptfds:被监控是否发异常   
  8. timeout:超时时间,Linux返回时会让改成剩余的工夫。  
  9. int:返回值,返回状态发生变化的叙说称的总和,错误返回-1,超时返回0。  

 

关于timeout:

 

[cpp] view
plain copy

 

  1. struct timeval结构如下:  
  2. struct timeval  
  3. {  
  4.        long tv_sec;  //seconds  
  5.        long tv_usec; //microseconds  
  6. };  

 

1,若timeout设置也t>0,表示等固定时间,有一个fd位被置为1或者时间耗尽,函数均归。
2,若timeout设置也t=0,表示非阻塞,函数检查得了每个fd后这回到。
3,若timeout设置为t=”NULL”,表示阻塞,直到来一个fd位被置为1函数才回。

[cpp] view
plain copy

 

  1. 连锁操作:    
  2. FD_ZERO(fd_set *set);         //fd_set很多系统实现吗bit arrays,将有着的文书讲述符从fd_set中清空    
  3. FD_CLR(int fd, fd_set *set);  //从set中清除fd      
  4. FD_SET(int fd, fd_set *set);  //将fd添加到set中     
  5. FD_ISSET(int fd, fd_set *set);//判断描述符fd是否在加的叙说符集set中,通常配合select函数使用,由于select函数成功返回时见面将未备好的叙述符位清零。通常我们采取FD_ISSET是为检查在select函数返回后,某个描述称是否准备好,以便进行接下的处理操作。       

常用代码:

 

[cpp] view
plain copy

 

  1. fd_set  rdfds;  
  2. struct timeval tv;  
  3. tv.tv_sec = 1;  
  4. tv.tv_uses = 500;  
  5. int ret;  
  6. FD_ZERO(&rdfds);  
  7. FD_SET(socket, &rdfds);  
  8. ret = select (socket + 1, %rdfds, NULL, NULL, &tv);  
  9. if(ret < 0)   
  10.  perror (“select”);  
  11. else if (ret == 0)   
  12.  printf(“time out”);  
  13. else {  
  14.        printf(“ret = %d/n”,ret);  
  15.        if(FD_ISSET(socket, &rdfds)){  
  16.        /* 读取socket句柄里的数据 */  
  17.        recv( );  
  18.        }  
  19. }  

3.5.3 函数pselect

 

[cpp] view
plain copy

 

  1. 函数原型:  
  2. #include <sys/select.h>  
  3. int pselect(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds,fd_set *restrict exceptfds, const struct timespec *restrict tsptr,const sigset_t *restrict sigmask);  
  4. 参数说明  
  5. 返回值:Returns: count of ready descriptors, 0 on timeout, -1 on error  

她同select的分别在于:
1,pselect使用timespec结构指定超时值。timespec结构为秒和纳秒表示时间,而非秒和微秒。
2,pselect的超时值被声称也const,这包了调用pselect不会见改变timespec结构。
3,pselect可采取一个只是摘的信号屏蔽字。在调用pselect时,以原子操作的法门安装该信号屏蔽字,在返时回升原先的信号屏蔽字。

 

3.5.4 函数poll

[cpp] view
plain copy

 

  1. 函数原型:  
  2. #include <sys/poll.h>  
  3. int poll (struct pollfd *fds, unsigned int nfds, int timeout);  
  4. 参数说明:  
  5. timeout:【值=INFTIM】表示永远等待【值=0】表示这回去,不死进程【值>0】等待指定数量的毫秒数。  

pollfd结构说明:

 

[cpp] view
plain copy

 

  1. struct pollfd {  
  2.      int fd; /* 文件讲述符 */  
  3.      short events; /* 等待的风波 */  
  4.      short revents; /* 发生的波 */  
  5. };  
  6. poll函数可用之测试值:  
  7. 常量  说明  
  8. POLLIN  普通或预先级带多少而读  
  9. POLLRDNORM  普通数据只是读  
  10. POLLRDBAND  优先级带多少可读  
  11. POLLPRI 高优先级数据而读  
  12. POLLOUT 普通数据只是写  
  13. POLLWRNORM  普通数据而写  
  14. POLLWRBAND  优先级带多少只是写  
  15. POLLERR 发生误  
  16. POLLHUP 发生挂于  
  17. POLLNVAL    描述字勿是一个开辟的公文  
  18. 在意:后三只只能作为描述字的归来结果存储于revents中,而休可知看做测试条件用于events中。  

 

 

3.5.5 函数epoll

共计有三只函数:

 

[cpp] view
plain copy

 

  1. int epoll_create(int size);  

创一个epoll的句柄,size用来报本是监听的数量一共发生多怪。这个参数不同于select()中之首先独参数,给起尽老监听的fd+1的价。需要专注的凡,当创建好epoll句柄后,它就是是会占一个fd值,在linux下如果翻开/proc/进程id/fd/,是能够见到这个fd的,所以在以完epoll后,必须调用close()关闭,否则可能致fd被耗尽。

[cpp] view
plain copy

 

  1. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);  

epoll的风波注册函数,它不同以及select()是当监听事件不时喻本而监听什么种的事件,而是以此地先登记要监听的风波类。第一独参数是epoll_create()的回到值,第二单参数表示动作,用三只宏来表示:
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改就注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd;
其三个参数是索要监听的fd,第四只参数是语本需要监听什么事。
struct epoll_event结构如下:

[cpp] view
plain copy

 

  1. struct epoll_event {  
  2.   __uint32_t events;  /* Epoll events */  
  3.   epoll_data_t data;  /* User data variable */  
  4. };  

events可以是以下几只庞大的汇:
EPOLLIN :表示对应之公文讲述吻合可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文本讲述吻合可以写;
EPOLLPRI:表示对应的文书讲述符有紧急的数只是读(这里应该代表来带动客数据来临);
EPOLLERR:表示对应的文件讲述符发生错误;
EPOLLHUP:表示对应的公文讲述称被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge
Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一糟事件,当监听结束这次事件后,如果还亟需后续监听者socket的语,需要更把这个socket加入到EPOLL队列里

[cpp] view
plain copy

 

  1. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);  

伺机事件之发生,类似于select()调用。参数events用来起水源得到事件之聚众,maxevents告的根本是events有差不多异常,这个
maxevents的价未可知压倒创建epoll_create()时的size,参数timeout是过时间(毫秒,0会立即回去,-1以不确定,也产生
说法说是永久阻塞)。该函数回需要处理的轩然大波数量,如归回0表示曾逾期。

 

 

 

在头里说过的客户/服务器程序中,服务器只能处理一个客户端的请,如何以服务多单客户端也?在未说到select/poll/epoll等高档IO之前,比较老土之法门是行使fork来兑现。网络服务器通常用fork来而服务多单客户端,父进程专门负责监听端口,每次accept一个新的客户端连接就fork出一个子过程专门服务这客户端。但是子进程退出时见面时有发生僵尸进程,父进程而专注处理SIGCHLD信号及调用wait清理僵尸进程,最简易的方法就是是一直忽略SIGCHLD信号。

1,这里为何会生僵尸进程?

2,实现P2P

3,signal(SIGCHLD, SIG_IGN);

相关文章