客户端和服务器实现全双工通讯,linux网络编制程序

By admin in 美高梅手机版4858 on 2019年4月28日

看了Linux程序设计四中文版,学习了多线程编制程序和socket编制程序。本文的主次参考自Linux程序设计四的第三5章。

互联网上存有素材都说epoll是高并发、单线程、IO重叠服用的首选架构,比select和poll品质都要好,特别是在有大气不活跃接连的情景下。具体原理就不演讲了,上面说说采纳。

安慕希组(ip地址,协议,端口)就能够标志互连网的进程

 

1、 有趣的事十二线程实现多个服务器和三个客户端落成全双工通讯

具备有八个函数:

 

规划了二个客户端程序,一个服务端程序。使用TCP协议举行多少传输。

服务器端创制八个线程:四个用以吸收接纳客户端发送过来的音信;3个用来给客户端发送音讯。

#include <sys/epoll.h>

三.一,OSI7层模型和TCP/IP伍层模型

 

OSI七层互连网模型由下至上为1至7层,分别为:

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

1.1 应用层,异常的粗略,正是应用程序。那1层负担分明通信对象,并保管由丰盛的财富用于通讯,那么些本来都以想要通讯的应用程序干的作业。 
1.2 表示层,肩负数据的编码、转化,确认保障应用层的符合规律化办事。那一层,是将大家看看的分界面与2进制间互相转化的地点,正是大家的语言与机器语言间的中间转播。数据的缩减、解压,加密、解密都发出在那1层。那1层依据分裂的运用目标将数据管理为不相同的格式,表现出来正是大家看看的无所不有的文件扩充名。 
1.3 会话层,负担建立、维护、调节会话,区分差别的对话,以及提供单工(Simplex)、半双工(哈尔f
duplex)、全双工(Full duplex)二种通讯格局的服务。大家平时所知的NFS,RPC,X
Windows等都干活在那1层。 
1.4 传输层,担任分割、组合数据,达成端到端的逻辑连接。数据在上三层是完全的,到了那1层开首被分割,那1层分割后的数额被叫作段(Segment)。叁遍握手(Three-way
handshake),面向连接(Connection-Oriented)或非面向连接(Connectionless-Oriented)的劳动,流控(Flow
control)等都产生在那壹层。 
1.5 网络层,担当管理网络地址,定位装置,决定路由。我们所熟练的IP地址和路由器就是干活在那一层。上层的数据段在这一层被细分,封装后叫做包(Packet),包有两种,一种名为用户数据包(Data
packets),是上层传下来的用户数量;另1种叫路由更新包(Route update
packets),是平昔由路由器发出来的,用来和别的路由器实行路由音信的置换。 
1.6 数量链路层,担当希图物理传输,CENCOREC校验,错误布告,互联网拓扑,流控等。我们所纯熟的MAC地址和沟通机都干活在那壹层。上层传下来的包在那一层被分割封装后叫做帧(Frame)。 
1.7 物理层,正是确凿的物理链路,担任将数据以比特流的格局发送、接收,就不多说了。 

 

客户端进程创建了二个客户端应用的socket,多个socket地址结构体。设置这一个socket地址结构体的端口和地点为要接二连三的服务端的端口和ip。然后选用客户端的socket尝试连接服务端(connect),倘若连接败北直接退出。如若总是成功,则使用那么些三番五次成功的socket进行数量传输(send和recv)。首先向服务端发送三个字节字符型数据,然后接过服务端十3个字节字符型数据,不断循环。假使发送和收受出错被擒获到的话(res=-一),关闭socket,退出进度。

客户端也开创多少个线程:贰个用于吸收接纳服务器端发送过来的音讯;八个用来给劳务器端发送音讯。

 

3.2,TCP握手

 

 

1、int epoll_create ( int size );

3.二.一 一次握手建立连接

在TCP/IP协议中,TCP协议提供可相信的连天服务,采取1遍握手建立一个接二连三。
1,客户端向服务器发送1个SYN J
贰,服务器向客户端响应1个SYN K,并对SYN J进行确认ACK J+1
3,客户端再想服务器发3个断定ACK K+一

美高梅手机版4858 1
从图中能够见见,当客户端调用connect时,触发了再三再四请求,向服务器发送了SYN
J包,那时connect进入阻塞状态;服务器监听到连年请求,即抽取SYN
J包,调用accept函数接收请求向客户端发送SYN K ,ACK
J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK
J+一之后,那时connect再次回到,并对SYN K进行确认;服务器收到ACK
K+一时,accept再次回到,至此壹回握手实现,连接建立。

二次握手的目的是起家双向的再三再四,第三遍握手是客户端向劳动器端发出请求 
第四回握手是服务器端告诉客户端,第一遍握手是马到成功的,即能够从客户端发送到客户端, 
其3回握手是客户端告诉服务器端,第三遍握手是打响的,就可以以从客户端到服务器端 
如此那般就保险了客户端和服务器端的双向通讯,

 

2、 以身作则代码

size是epoll要监视的fd的框框。

3.2.二 柒遍握手释放连接

美高梅手机版4858 2

一,有些应用进程首先调用close主动关闭连接,这时TCP发送3个FIN M;
二,另1端接收到FIN
M之后,试行被动关闭,对这一个FIN进行确认。它的吸收也视作文件停止符传递给应用进度,因为FIN的接收意味着应用进程在对应的连年上再也接到不到额外数据;
三,壹段时间之后,接收到文件截至符的利用过程调用close关闭它的socket。那导致它的TCP也发送二个FIN
N;
4,接收到这些FIN的源发送端TCP对它进行确认。

服务端程序接纳了一个sever_socket,并把那个socket与本机的ip和监听的端口实行绑定,并监听那些socket,accept远端来的连年。Accept成功一遍就会获得2个client_socket。那时创造三个新线程,并把这一个那么些client_socket作为线程参数字传送给新线程。1个新线程服务2个远端连接,管理他们的数目传输请求(不断的收发数据,循环)。

劳动器端的代码client.c

 

3.3,socket编程

先从劳动器端聊起。服务器端先开首化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在此时假诺有个客户端开头化四个Socket,然后连接服务器(connect),若是总是成功,那时客户端与服务器端的接连就确立了。客户端发送数据请求,服务器端接收请求并拍卖请求,然后把回应数据发送给客户端,客户端读取数据,最终关闭连接,三回交互停止。

gcc client2.c -o client2 -lpthread

#include <sys/types.h>

2、int epoll_ctl ( int epfd, int op, int fd, struct epoll_event
*event );

3.3.1 AF_INET TCP传输最简易版本

美高梅手机版4858 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=666陆)  
  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

 

[美高梅手机版4858,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  

 

gcc server2.c -o server2 -lpthread

#include <sys/socket.h>

(1)epfd:epoll_create的再次回到值。

3.三.二 参预重返值检查和IP地址

tcp_client.c

 

[cpp] view
plain copy

 

  1. #客户端和服务器实现全双工通讯,linux网络编制程序。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()绑定3个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. }  

 

 

#include <stdio.h>

(二)op  钦命操作类型:

3.3.3 AF_INET UDP传输最轻便易行版本

美高梅手机版4858 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. }  

 

以此客户和服务端程序有三个很离奇的气象,就是服务端运维未来,接收客户端的连年,各种连接创设二个新线程进行劳动。当有四个客户端程序连接服务端(展开多少个终端窗口开程序),全部的客户端都在疯狂与服务端举办数据传输时,把内部一个客户端程序(Ctrl+C)掉,那时服务端的进程也会应声终止,而服务端的终止会有关把其余正在传输数据的客户端进度一齐终止掉。对应的失误的客户端和服务端的代码为如下所示。(PS:停止掉客户端不是历次都让服务端挂掉,有时候会使得劳动端recv出错重临-一,被抓获,然后安全退出线程,进程依旧安全。)

#include <stdlib.h>

     EPOLL_CTL_ADD:以前的事件表中注册fd上的轩然大波

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. }  

 

 

#include <errno.h>

     EPOLL_CTL_MOD:修改fd上的注册事件

三.四 互联网编制程序函数

Unix/Linux基本教育学之1正是“一切皆文件”,都得以用“打开open –>
读写write/read –> 关闭close”

 

[plain] view
plain copy

 

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

 

 

#include <string.h>

     EPOLL_CTL_DEL:删除fd上的挂号事件

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:重回值为-一象征出错  

留神:并不是上边的type和protocol可以率性组合的,如SOCK_STREAM不可能跟IPPROTO_UDP组合。当protocol为0时,会活动选取type类型对应的暗许协议。

 

本着这么些现象本身做了有个别测试。1、把客户端改为只收,服务端改为只发。

#include <unistd.h>

(3)fd:要操作的文件讲述符(socket)

3.4.2 函数bind

命名套接字:bind()函数把二个地址族中的特定地点赋给socket。比如对应AF_INET、AF_INET6正是把2个ipv四或ipv陆地址和端口号组合赋给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:重回值,-一表示出错  

 

[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,互连网地址为INADD奥迪Q5_ANY,这些宏表示本地的放四IP地址,因为服务器可能有三个网卡,每个网卡也说不定绑定五个IP地址,那样设置能够在全体的IP地址上监听,直到与有个别客户端建立了连年时才鲜明下来到底用哪个IP地址,端口号为518捌。

 

(客户端崩掉会促成服务端的send的res=-一,百分之百被抓获到,从而安全退出线程,不会劫持整个进度。

#include <netinet/in.h>

 (4)event:内定要监听fd的怎么着业务。它是epoll_event结构指针类型:

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。你可以设置为伍要么10。当出错开上下班时间,listen()将会回去-一值。

本条函数对于backlog的阐述《unix网络编制程序》P八五是说已成功连接队列(ESTABLISHED)和未到位连接队列(SYN_奥迪Q3CVD)之和(即等待连接数而非连接数)。服务器调用的accept()重返并接受这几个一而再,假若有大气的客户端发起连接而服务器来不比管理,尚未accept的客户端就处于连接等待情况,listen()表明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接等待情形,要是接到到更加多的总是请求就大体。在Computer早期由于互连网连接的管理速度非常的慢,几个冒出的呼吁就恐怕导致系统管理不东山再起而引发错误,以后这些数字的意思早已非常的小了,未来软硬件质量差不离能担保那几个行列不或者满。连接的图景变为ESTABLISHED之后(实际是接2连3由从半一连队列转移到了形成握手的姣好队列)才表示能够被accpet()管理。

服务端崩掉会导致客户端recv出错为0,但从未被擒获,使得客户端在收不到数据的状态下直接死循环。客户端从未阻塞,recv的重返值是0。)

#define SERVPORT 3333

struct epoll_event

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:再次回到值,-一象征出错  

调用accept()之后,将会回去三个全新的套接口文件讲述符来管理那个单个的总是。那样,对于同2个接连来说,你就有了多少个文本讲述符。原先的一个文本讲述符正在监听你钦命的端口,新的文件讲述符能够用来调用send()和recv()。

能够通过对套接字文件讲述符设置O_NONBLOCK来改造其是或不是封堵:

 

[cpp] view
plain copy

 

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

 

 

 

#define BACKLOG
十                 //请求队列中的最大请求数

{

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)。

 

2、把客户端改为只发,服务端只收。

#define MAX_CONNECTED_NO 十  //最大是12八台Computer延续

     __unit32_t events;    // epoll事件

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);  

(客户端崩掉会促成服务端recv出错为0,但尚无被破获,从而多少个线程不可能退出,在死循环。

#define MAXDATASIZE 100

     epoll_data_t data;     // 用户数据

3.4.7 函数close

 

[plain] view
plain copy

 

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

留意:close操作只是使相应socket描述字的引用计数-一,唯有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

服务端崩掉会产生客户端send出错为-壹,被捕获,从而安全退出。)

 

};

3.4.8 函数getsockname

函数再次回到与套接口关联的本土协议地址。

 

[plain] view
plain copy

 

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

 

 

void pthread_recv(void *arg);

events:描述事件类型。events能够是以下多少个宏的会面:

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:重返值,-一意味着出错  

 

从而地方的稀奇奇异现象出现的来由是:

void Pthread_send(void * arg);

 EPOLLIN :表示对应的文件讲述符能够读(包含对端SOCKET平常关闭);
EPOLLOUT:表示对应的文本讲述符能够写;

在对端崩溃之后,send出错只会回来-一,而recv出错有时回来-1,大繁多时候重回0。唯有在recv出错为0一直不被擒获,而又继续send,才会招致进程马上过逝(此时不能够捕获send的错误)。

 

 EPOLLPBMWX伍I:表示对应的文书讲述符有迫切的数量可读(那里应该代表有带外数据来临);
EPOLLE本田UR-VXC60:表示对应的文件讲述符产生错误;

3.5 互连网字节序与主机字节序转变

将主机字节序调换为互连网字节序(防止四头小端难题)

#include <netinet/in.h>

消除办法是:

int main()

EPOLLHUP:表示对应的公文讲述符被挂断;

3.5.1 函数htonl

 

[plain] view
plain copy

 

  1. uint32_t htonl(uint32_t hostlong);  

 

两端的程序扩大捕获recv的出错为0的意况,具体代码是if((res==-一)||(res==0))。那样不管哪端崩掉,对端都能够捕获出错的事态,管理失误的情状,不会油不过生进程突然离世现象。

{

 EPOLLET: 将EPOLL设为边缘触发(艾德ge
Triggered)情势,那是周旋于水平触发(Level Triggered)来讲的。

3.5.2 函数htons

 

 

[plain] view
plain copy

 

  1. uint16_t htons(uint16_t hostshort);  

 

 

         struct sockaddr_in
server_sockaddr,client_sockaddr;

EPOLLONESHOT:只监听三遍事件,当监听完此番风浪今后,假若还要求连续监听那些socket的话,需求再行把这几个socket加入到EPOLL队列里。

3.5.3 函数ntohl

 

[plain] view
plain copy

 

  1. uint32_t ntohl(uint32_t netlong);  

 

 

 

         int sockfd,client_fd,sin_size,ret;

data成员:个中data.fd常用来装要操作的fd。

3.5.4 函数ntohs

[plain] view
plain copy

 

  1. uint16_t ntohs(uint16_t netshort);  

 

Client2.C程序:

         pthread_t id1,id2;

 

3.陆 IP地址与主机字节序转变

 

#include <sys/types.h>

         sin_size =sizeof(struct sockaddr);

typedef union epoll_data

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:再次来到值:假使函数出错将回来2个负值,并将errno设置为EAFNOSUPPORT,假如参数af钦定的地址族和src格式不对,函数将重回0。  

 

#include <sys/socket.h>

         //struct sockaddr_in
server_sockaddr,client_sockaddr;

{

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);  

 

#include <stdio.h>

         //建立二个socket连接

     void *ptr;

三.7 主机数据库函数

#include <netinet/in.h>

     //近来都是AF_INET(ipv4);SOCK_STREAM(TCP),如果是UDP,则SOCK_DGRAM

      int fd;

3.7.1 函数gethostname

它回到(本地)Computer的名字,存款和储蓄在hostname中,大小为size

 

[plain] view
plain copy

 

  1. 函数原型:  
  2. int gethostname(char*hostname,size_tsize);  
  3. 参数表明:  
  4. int:重回值gethostname将重临0。假若失利,它将回到-一。   

#include <arpa/inet.h>

         if((sockfd =
socket(AF_INET,SOCK_STREAM,0))==-1){

      __uint32_t u32;

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发生错误,再次来到一 */  
  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. }   

 

#include <unistd.h>

                   perror(“socket”);

      __uint64_t u64;

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。  

 

 

#include <stdlib.h>

                   exit(1);

  } epoll_data_t;

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产生错误,再次回到一 */  
  25.     }  
  26.     if ( (servinfo = getservbyname(“daytime”,”tcp”)) );  
  27.     {  
  28.         printf(“no daytime service/n”);  
  29.         exit(1); /* 如若调用getservbyname发生错误,再次回到一 */  
  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. }   

int main(int argc,char* argv[])                         

         printf(“socket
success!,sockfd=%d\n”,sockfd);

 

叁.5 多客户编制程序

{  
                                       //测试方法,把client贰和server二放在同等

         //bind用于地点IP地址和端口的绑定

3、int epoll_wait ( int epfd, struct epoll_event* events, int
maxevents, int timeout );

3.伍.一 阻塞与非阻塞

(1)阻塞block
   
所谓阻塞方式block,顾名思义,正是经过也许线程推行到这么些函数时必须等待有些事件的发出,假设事件尚无产生,进度或线程就被堵塞(进度Sleep),函数无法马上回去。
    举例socket编制程序中connect、accept、recv、recvfrom那样的堵塞程序。
   
再如大多数的函数调用、语句实践,严俊来讲,他们都以以堵塞形式举行的。
(2)非阻塞non-block
   
所谓非阻塞形式non-block,便是进度或线程推行此函数时无需非要等待事件的发生,一旦实行一定回来,以重回值的不如来反映函数的执市价况,倘使事件发生则与阻塞格局同样,若事件尚无生出则赶回2个代码来告诉事件未生出,而经过或线程继续实施,所以功效较高。
 
 非阻塞I/O有三个缺点,要是具备设施都一向未曾数量达到,调用者须求频仍查询做无用功,假诺打断在那边,操作系统能够调治别的进度实行,就不会做无用功了。?????

int sockfd;                              //也许差异文件夹下都能够

         server_sockaddr.sin_family=AF_INET;

epoll_wait的行事流程是:等待,假若有epoll事件发生马上回去,不然等待timeout阿秒。重回时拷贝要管理的轩然大波到events指向的数组,重返就绪的文件讲述符的个数,退步时回来-一并安装errno。 

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:为文件讲述符集结中的最大值+壹,幸免函数检查fd_set的所有1024位  
  5. readfds:被监察和控制是还是不是足以读   
  6. writefds:被监察和控制是还是不是能够写   
  7. exceptfds:被监督是不是产生尤其   
  8. timeout:超时时间,Linux再次回到时会被改变成剩余的时光。  
  9. int:重返值,再次来到状态产生变化的讲述符的总量,错误重临-一,超时重回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,表示等待固定时期,有3个fd位被置为一恐怕时间耗尽,函数均重临。
2,若timeout设置为t=0,表示非阻塞,函数检查完各类fd后立时回去。
叁,若timeout设置为t=”NULL”,表示阻塞,直到有贰个fd位被置为一函数才回来。

[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. }  

         int len,i,res;                            
//2个极端运转./client二  其余多个终极

         server_sockaddr.sin_port=htons(SERVPORT);

timeout:钦定epoll的晚点时间,单位是阿秒。当timeout为-壹是,epoll_wait调用将永恒阻塞,直到有个别事件爆发。当timeout为0时,epoll_wait调用将随即回到。 

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的分裂在于:
一,pselect使用timespec结构钦定超时值。timespec结构以秒和飞秒表示时间,而非秒和飞秒。
2,pselect的超时值被声称为const,那保障了调用pselect不会转移timespec结构。
3,pselect可应用一个可挑选的复信号屏蔽字。在调用pselect时,以原子操作的主意安装该确定性信号屏蔽字,在回去时回涨原先的实信号屏蔽字。

 

         struct sockaddr_in address;                //运转  ./server二就足以看来结果了

         server_sockaddr.sin_addr.s_addr=INADDR_ANY;
        //htonl(INADDR_ANY)

maxevents:钦赐最多监听多少个事件。假诺events指向的是二十一个单元的结构体数组,那么就安装maxevents为20。 

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. POLL凯雷德DNO汉兰达M  普通数据可读  
  10. POLLPAJERODBAND  优先级带多少可读  
  11. POLLP路虎极光I 高优先级数据可读  
  12. POLLOUT 普通数据可写  
  13. POLLW奔驰G级NO奔驰M级M  普通数据可写  
  14. POLLWRBAND  优先级带多少可写  
  15. POLLECRUISER宝马7系 发生错误  
  16. POLLHUP 爆发挂起  
  17. POLLNVAL    描述字不是一个开垦的文书  
  18. 留神:后四个只可以当作描述字的回来结果存款和储蓄在revents中,而不能够同日而语测试条件用于events中。  

 

 

         int result;

     bzero(&(server_sockaddr.sin_zero),8);

events:
events指向的数组元帅拷贝全部就绪的事件,从基础事件表中。events的分子是struct
epoll_event类型,一般包括events(其值是如:EPOLLIN、EPOLLOUT等)。还有3个是data.fd,包括拷贝的事件对应的socket,假使是服务器监听socket,表达是有用户连接到那一个socket,假如是别的已经接二连三好的socket,表达是有数量要发送或然吸收。

3.5.5 函数epoll

总共有多个函数:

 

[cpp] view
plain copy

 

  1. int epoll_create(int size);  

创办3个epoll的句柄,size用来告诉内核这么些监听的多寡壹共有多大。这一个参数不一致于select()中的第2个参数,给出最大监听的fd+一的值。供给专注的是,当创造好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中去除1个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:表示对应的文件讲述符能够写;
EPOLLPHavalI:表示对应的文件讲述符有迫切的数码可读(那里应该代表有带外数据来临);
EPOLLEMuranoLX570:表示对应的文书讲述符发生错误;
EPOLLHUP:表示对应的文书讲述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(艾德ge
Triggered)方式,那是争辩于水平触发(Level Triggered)来讲的。
EPOLLONESHOT:只监听1回事件,当监听完这一次事件未来,假若还亟需延续监听那个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会立时回到,-一将不明显,也有
说法说是恒久阻塞)。该函数重临需求管理的风云数量,如重返0表示已过期。

 

 

 

在前方讲过的客户/服务器程序中,服务器只好管理三个客户端的乞求,如何同时服务多个客户端呢?在未讲到select/poll/epoll等高端IO从前,相比老土的点子是使用fork来落成。互联网服务器一般用fork来还要服务多少个客户端,父进度专责监听端口,每一次accept多个新的客户端连接就fork出一个子进度专门服务那些客户端。然则子进程退出时会发生僵尸进程,父进度要小心管理SIGCHLD时域信号和调用wait清理僵尸进度,最简易的办法正是一向忽略SIGCHLD频限信号。

一,那里为何会有僵尸进度?

2,实现P2P

3,signal(SIGCHLD, SIG_IGN);

         char ch = ‘A’;                       
//奇异,1个client运转多个本子,每一遍获得的

         //把本端的音讯绑定

假设事件数组中的数据得到处理,那么内核事件表中的风云就会被删去,下次wait就未有这几个socket的事件了。 

         char buff[1024];                    
//居然是同一个socket。改个名字也不行

         if(bind(sockfd,(struct sockaddr
*)&server_sockaddr,sizeof(struct sockaddr))==-1)

 

        

      {              

实例代码:

         sockfd = socket(AF_INET,SOCK_STREAM,0);              //

           perror(“bind”);

epoll.c

         printf(“socket is %d\n”,sockfd);

               exit(1);

#include <stdio.h>

         address.sin_family = AF_INET;

         }

#include <sys/epoll.h>

         address.sin_addr.s_addr = inet_addr(“192.168.131.129”);

         printf(“bind success!\n”);

#include <sys/socket.h>

         address.sin_port = htons(9734);

         if(listen(sockfd,BACKLOG)==-1)

#include <stdlib.h>

         len = sizeof(address);

     {

#include <netinet/in.h>                 //包含sockaddr_in定义

        

                   perror(“listen”);

#include <errno.h>

         result = connect(sockfd,(struct sockaddr*)&address,len);

                   exit(1);

#include <string.h>                     //包含memset strncpy

         if(result == -1)

         }

 

         {

         printf(“listening….\n”);

 

                   perror(“oops:client1”);

     //接受并保留客户端的音讯

int main(int argc,char* argv[])   //主函数

                   exit(-1);

         if((client_fd=accept(sockfd,(struct
sockaddr *)&client_sockaddr,&sin_size))==-1)

{

         }

     {                

 

        

perror(“accept”);

      int epfd1;int result;

         memset(buff,0,1024);

                exit(1);

      int server_len,client_len;

         i = 0;

         }

      int server_sockfd,client_sockfd;

         //for(i=0;i<100;i++)

         printf(“client_fd=%d”,client_fd);

      struct sockaddr_in server_address;       //定义在
<netinet/in.h>

         for(;;)

         pthread_create(&id1,NULL,(void *)
pthread_recv,(void*)&client_fd);

      struct sockaddr_in client_address;

         {

         if(ret != 0)

      struct epoll_event ev1;

                  

                   perror(“pthread_recv
creat”);

      struct epoll_event ev[20];

                  

         ret=pthread_create(&id2,NULL,(void
*)Pthread_send,(void*)&client_fd);

      int epollreturn;

                   res = send(sockfd,&ch,1,0);

         if(ret != 0)

      int i,j,res;

                   if(res==-1)

                   perror(“Pthread_send
creat”);

      int sockfd;

                   {

         pthread_join(id1,NULL);

      char ch = ‘0’;

                            printf(“send error,res is %d,exiting
program\n”,res);

         pthread_join(id2,NULL);

      char buff[1024];

                            close(sockfd);

         close(sockfd);

     

                            return(-1);

}

      server_address.sin_family = AF_INET;

                   }

 

      server_address.sin_addr.s_addr = inet_addr(“192.168.131.129”);

                  

//服务器发送线程

      server_sockfd = socket(AF_INET,SOCK_STREAM,0);

                   i++;

void Pthread_send(void * arg)

      server_address.sin_port = htons(9734);

                   memset(buff,0,102);

{

      server_len = sizeof(server_address);

                   res = recv(sockfd,buff,102,0);          

         int buf_len, client_fd,sendbytes;

      client_len = sizeof(client_address);

                   if(res==-1)                        
//if((res==-1)||(res==0))

         char buf[MAXDATASIZE];

     

                   {

         client_fd = *((int *)arg);

      result = bind(server_sockfd,(struct
sockaddr*)&server_address,server_len);

                            printf(“recv error,res is %d,exiting
program\n”,res);

         printf(“server send: “);

      if(result!=0)

                            close(sockfd);

         while(1)

      {

                            return(-1);

         {       

           printf(“bind failed\n”);

                   }

                   fgets(buf,MAXDATASIZE,stdin);

           exit(1);                             //在stdlib.h

                   printf(“socket:%d,buff is %s,i is
%d\n”,sockfd,buff,i);

                   buf_len =sizeof(buf);

      }   

                   /**/

                   if((sendbytes = send(client_fd
,buf,buf_len,0))==-1)

 

 

                   {

     

         }

                            perror(“send”);

     

        

                            exit(1);

      epfd1 = epoll_create(10000);

         printf(“exiting program\n”);

                   }

      ev1.data.fd = server_sockfd;

         close(sockfd); 

                   if(!strncmp(buf,”end”,三))         //只相比字符串的前多少个字符

      ev1.events = EPOLLIN;

         return 0;

                            break;

      /*

}

                   sleep(2);

      printf(“%08x\n”,EPOLLIN);

 

         }

      printf(“%08x\n”,EPOLLOUT);

 

                           

      printf(“%08x\n”,EPOLLPRI);

 

}

      printf(“%08x\n”,EPOLLERR);

Server2.C程序:

 

      printf(“%08x\n”,EPOLLHUP);

#include <sys/types.h>

//服务器接收数据线程

      printf(“%08x\n”,EPOLLET);

#include <sys/socket.h>

void pthread_recv(void *arg)

      printf(“%08x\n”,EPOLLONESHOT);

#include <stdio.h>

{

      */

#include <netinet/in.h>

         int buf_len, client_fd,recvbytes;

      epoll_ctl(epfd1,EPOLL_CTL_ADD,server_sockfd,&ev1);

#include <arpa/inet.h>

         char buf[MAXDATASIZE];

     

#include <unistd.h>

         client_fd = *((int *)arg);

     

#include <stdlib.h>

     //接收服务端发来的音讯

     

#include <pthread.h>

         while(1)

      result = listen(server_sockfd,5);

 

         {

      if(result!=0)

void* thread1(void* arg)

                   if((recvbytes = recv(client_fd
,buf,MAXDATASIZE,0))==-1)

      {

{

                   {

           printf(“listen failed\n”);

         int client_sock;

                            perror(“recv”);

           exit(1);

         char buff[1024];

                            exit(1);

      }

         char ch;

                   }

     

         int i,res;

                   else

      memset(buff,0,1024);

 

                   {

      strncpy(buff,”this is server”,14);

         memset(buff,0,1024);

                            buf[recvbytes]=0;

     

         strncpy(buff,”this is server”,14);

                            printf(“server received
data from server is :%s\n”,buf);

      for(;;)

         client_sock = (int)arg;     

                            if(!strncmp(buf,”end”,三))         //只比较字符串前四个字符

      {   

         printf(“para from main thread,socket = %d\n”,client_sock);

                                     break;

           epollreturn  = epoll_wait(epfd1,ev,20,4000);

         printf(“before sending,buff is:%s\n”,buff);

                   }

           printf(“epollreturn is %d\n”,epollreturn);

         //for(i=0;i<100;i++)

                   sleep(1);

           if(epollreturn>0)

         for(;;)                                                  

         }

           {

         {                                                       

}

                 for(i=0;i<epollreturn;i++)

                   //res =
read(client_sock,&ch,1);                         

 

                 {

                   //if(res==-1)                                       

客户端的代码:

                     

                   //{                                                 

#include <stdio.h>

                    
if(ev[i].data.fd==server_sockfd)//要是新监测到多个SOCKET用户连接到了绑定的SOCKET端口,建立新的连天。

                   //      printf(“read error\n”);

#include <stdlib.h>

                      {

                   //      close(client_sock);

#include <errno.h>

                           

                   //      break;

#include <string.h>

                            client_sockfd =
accept(server_sockfd,(struct sockaddr *)&client_address,
&client_len);//未有总结client_len的值,会导致accept返回-1

                   //      //pthread_exit((void*)(-1));

#include <netdb.h>

                            printf(“accept one
client,socket:%d\n”,client_sockfd);                        

                   //}

#include <sys/types.h>

                            ev1.data.fd=client_sockfd;

                  

#include <netinet/in.h>

                            ev1.events=EPOLLIN;

                  

#include <sys/socket.h>

                           
epoll_ctl(epfd1,EPOLL_CTL_ADD,client_sockfd,&ev1);

                  

 

                           

                   res =
recv(client_sock,&ch,1,0);                     

#define SERVPORT 3333

                            //ev1.data.fd=client_sockfd;

                   if(res==-1)

#define MAXDATASIZE 100

                            //ev1.events=EPOLLOUT;

                  
//if((res==-1)||(res==0))                              

 

                           
//epoll_ctl(epfd1,EPOLL_CTL_ADD,client_sockfd,&ev1); //注册

                   {       
                                             

void pthread_recv(void *arg);

                      }

                            printf(“recv error!res is
%d\n”,res);            

void Pthread_send(void * arg);

                      else
if(ev[i].events&EPOLLIN)//借使是早就一而再的用户,收到数额,那么举行读入。

                           
close(client_sock);                              

 

                      {

                            break;

main(int argc,char *argv[]){

                            sockfd = ev[i].data.fd;

                           
//pthread_exit((void*)(-1));                       

         int sockfd,sin_size,ret;

                            if (sockfd < 0)

                   }

         struct hostent *host;

                            {

                  

         pthread_t id1,id2;

                                  printf(“EPOLLIN,sockfd < 0\n”);

                  

         struct sockaddr_in
serv_addr;         //套接字的地点结构

                                  continue;

                   res = send(client_sock,buff,102,0);         
        

         struct sockaddr_in server_sockaddr;

                            }

                   if(res==-1)                                          

        

                            res = recv(sockfd,&ch,1,0);

                                                                        

         if(argc < 2)

                                                       

                   {                                                    

    {

                            if (res < 0)

                            printf(“send error,res is %d\n”,res);

                   fprintf(stderr,”Please enter the
server’s hostname!\n”);

                            {

                            close(client_sock);

                   exit(1);

                                 if (errno == ECONNRESET)

                            break;

         }       

                                  {

                            //pthread_exit((void*)(-1));

     //AF_INET:使用的是IPV4

                                       close(sockfd);

                   }

     //SOCK_STREAM:流式套接字

                                       ev[i].data.fd = -1;

                   /**/

         if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)

                                       printf(“EPOLLIN,res<0,errno ==
ECONNRESET\n”);

                  

     {

                                  }

         }

          perror(“socket”);

                                  else

         printf(“exiting thread\n”);

                 exit(1);

                                  printf(“EPOLLIN,recv error,res
<0\n”);

         close(client_sock);

         }

                            }

         return ((void*)0);

         printf(“sockfd=%d\n”,sockfd);

                            else if (res == 0)

}

         serv_addr.sin_family=AF_INET;

                            {

 

         serv_addr.sin_port=htons(SERVPORT);

                                  close(sockfd);                   
//个测试发掘关闭socket,epoll队列中就不再监视这些socket了,就像不须求删除监视

int main(int argc,char* argv[])

     //serv_addr.sin_addr=*((struct in_addr
*)host->h_addr);

                                  ev[i].data.fd = -1;

{

     //host->h_addr强制类型转换;建议直接选择上边包车型地铁不二等秘书籍

                                  printf(“EPOLLIN,res == 0\n”);

         int result,re;

         serv_addr.sin_addr.s_addr=inet_addr(argv[1]);   //”127.0.0.1″);       Internet地址

                                  ev1.data.fd=sockfd;

         pthread_t a_thread;

         bzero(&(serv_addr.sin_zero),8);

                                  ev1.events=EPOLLIN;

         int server_sockfd,client_sockfd;

     //连接

                                 
epoll_ctl(epfd1,EPOLL_CTL_DEL,sockfd,&ev1);

         int server_len,client_len;

         if(connect(sockfd,(struct sockaddr
*)&serv_addr,sizeof(struct sockaddr))==-1)

                            }

         struct sockaddr_in server_address;

         {

                            else

         struct sockaddr_in client_address;

                   perror(“connect”);

                            {

 

                   exit(1);

                                  printf(“EPOLLIN,receive one char
%c,socket is %d\n”,ch,sockfd);

         server_sockfd = socket(AF_INET,SOCK_STREAM,0);

         }

                            }

         server_address.sin_family = AF_INET;

         ret=pthread_create(&id1,NULL,(void
*)Pthread_send,(void*)&sockfd);

 

         server_address.sin_addr.s_addr =
inet_addr(“192.168.131.129”);

         if(ret != 0)

                            ev1.data.fd=sockfd; 

         server_address.sin_port = htons(9734);        
//注意那里的sin_port是多个字节的

                   perror(“Pthread_send
creat”);

                            ev1.events=EPOLLOUT;

         server_len = sizeof(server_address);

         pthread_create(&id2,NULL,(void *)
pthread_recv,(void*)&sockfd);

                           
epoll_ctl(epfd1,EPOLL_CTL_MOD,sockfd,&ev1);

        

         if(ret != 0)

                            /**/

         result = bind(server_sockfd,(struct
sockaddr*)&server_address,server_len);

                   perror(“pthread_recv
creat”);

                      }

         if(result!=0)

         pthread_join(id1,NULL);

                     

         {

         pthread_join(id2,NULL);

                      else if(ev[i].events&EPOLLOUT) //
监测数据发送的法则是,对端调用recv,文告到服务器端,布告epoll,这一个socket有多少要发。

                   printf(“bind failed\n”);

         close(sockfd);

                      {

                   exit(1);

}

                            sockfd = ev[i].data.fd;

         }       

 

                            res = send(sockfd,buff,102,0);

         result = listen(server_sockfd,5);

//客户端发送数据线程

                            if(res==-1)

         if(result!=0)

void Pthread_send(void * arg)

                            {

         {

{

                                  printf(“send error,res is %d\n”,res);

                   printf(“listen failed\n”);

         int buf_len, sockfd,sendbytes;

                                  close(sockfd);

                   exit(1);

         char buf[MAXDATASIZE];

                                  ev1.data.fd=sockfd;

         }

         sockfd = *((int *)arg);

                                  ev1.events=EPOLLOUT;

        

         printf(“client send: “);

                                 
epoll_ctl(epfd1,EPOLL_CTL_DEL,sockfd,&ev1);

         while(1)

         while(1)

                            }

         {

         {       

                           

                   char ch;

                   fgets(buf,MAXDATASIZE,stdin);

                           

                   printf(“server waiting\n”);

                   buf_len =sizeof(buf);

                            ev一.data.fd=sockfd;
//设置用于读操作的文本讲述符

                   client_len = sizeof(client_address);

                   if((sendbytes =
send(sockfd,buf,buf_len,0))==-1)

                            ev壹.events=EPOLLIN;
//设置用于注测的读操作事件

                   client_sockfd = accept(server_sockfd,(struct
sockaddr *)&client_address,&client_len);

                   {

                           
epoll_ctl(epfd1,EPOLL_CTL_MOD,sockfd,&ev壹); 
//修改sockfd上要拍卖的风云为EPOLIN

                   printf(“accept one
client,socket:%d\n”,client_sockfd);

                            perror(“send”);

                           

                  

                            exit(1);

                      }

                   re =
pthread_create(&a_thread,NULL,thread1,(void*)client_sockfd);    

                   }

                

                  
if(re!=0)                                                            

                   if(!strncmp(buf,”end”,3))         //只相比较字符串的前八个字符

                

                  
{                                                                     

                            break;

                 }

                            printf(“create thread
failed\n”);                                 

                   sleep(2);

          

                            exit(EXIT_FAILURE);           

         }                   

          

                   }

}

           }

                   //read(client_sockfd,&ch,1); 

 

          

                   //ch++;

//客户端接收数据线程

     

                   //write(client_sockfd,&ch,1);

void pthread_recv(void *arg)

     

                   //close(client_sockfd);

{

      }

         }

         int buf_len, sockfd,recvbytes;

      return 0;

        

         char buf[MAXDATASIZE];

}

         return 0;

         sockfd = *((int *)arg);

 

}

     //接收服务端发来的新闻

 

 

         while(1)

client2.c

 

         {

#include <sys/types.h>

                   if((recvbytes =
recv(sockfd,buf,MAXDATASIZE,0))==-1)

#include <sys/socket.h>

                   {

#include <stdio.h>

                            perror(“recv”);

#include <netinet/in.h>

                            exit(1);

#include <arpa/inet.h>

                   }

#include <unistd.h>

                   else

#include <stdlib.h>

                   {

#include <string.h>                     //包含memset strncpy

                            buf[recvbytes]=0;

 

                           printf(“client received
data from server is :%s\n”,buf);

int main(int argc,char* argv[])                         //

                            if(!strncmp(buf,”end”,三))         //只比较字符串的前多少个字符

{                                                       //

                                     break;

      int sockfd;                                         // 

                   }

      int len,i,res;

                   sleep(1);

      struct sockaddr_in address;

         }

      int result;

}

      char ch = ‘A’;

      char buff[1024];

     

      sockfd = socket(AF_INET,SOCK_STREAM,0);             
//奇怪,2个client运行多少个版本,每一次获得的竟是是同三个socket。改个名字也特别

      printf(“socket is %d\n”,sockfd);

      address.sin_family = AF_INET;

      address.sin_addr.s_addr = inet_addr(“192.168.131.129”);

      address.sin_port = htons(9734);

      len = sizeof(address);

     

      result = connect(sockfd,(struct sockaddr*)&address,len);

      if(result == -1)

      {

           perror(“oops:client1”);

           exit(-1);

      }

     

      memset(buff,0,1024);

      i = 0;

      //for(i=0;i<10;i++)

      for(;;)

      {  

           res = send(sockfd,&ch,1,0);

           if(res==-1)

           {

                 printf(“send error,res is %d,exiting program\n”,res);

                 close(sockfd);

                 return(-1);

           }

           /**/ 

           i++;

            memset(buff,0,102);

           res = recv(sockfd,buff,102,0); 

          

            //if((res==-1)||(res==0))

           if(res==-1)                       

           {

                 printf(“recv error,res is %d,exiting program\n”,res);

                 close(sockfd);

                 return(-1);

           }

           printf(“socket:%d,buff is %s,i is %d\n”,sockfd,buff,i);

           /**/

      }

      //scanf(“%s”,buff);

      printf(“exiting program\n”);

      close(sockfd);  

      return 0;

}

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有