http://blog.csdn.net/qq_25425023/article/details/53914820
回射服務器就是服務端將客戶端的數據發送回去。
??
? 我實現的回射服務器返回增加了時間。
? 服務端代碼,可以很容易看懂:
?
- #include?<sys/socket.h>??
- #include?<stdio.h>??
- #include?<string.h>??
- #include?<sys/types.h>??
- #include?<netinet/in.h>??
- #include?<time.h>??
- #include?<unistd.h>??
- #include?<arpa/inet.h>??
- #include?<stdlib.h>??
- ??
- #include?"../thread_pool.h"??//在上一篇博客中??
- ??
- #define?MAX_BUFFER?512??
- ??
- typedef?struct?sockaddr?SSA;??
- ??
- char?timebuffer[50];??//存儲時間??
- char?readbuffer[MAX_BUFFER];???//存儲客戶端數據??
- time_t?tick;??
- //任務類??
- class?task??
- {??
- private:??
- ????int?connfd;??//與客戶端連接的文件描述符??
- public:??
- ????task(int?conn)?:?connfd(conn)??
- ????{??
- ????}??
- ????~task(){}??
- ??
- ????void?doit()??//線程池調用函數??
- ????{??
- ????size_t?readsize;??
- ????while((readsize?=?read(connfd,?readbuffer,?MAX_BUFFER))?>?0)??//讀取客戶端數據??
- ????{??
- ????????printf("%ld?get?%dbyte\n",(unsigned?long)pthread_self()??
- ?????????,?(int)readsize);???//測試用??
- ????????if(readsize?==?-1)??//read出錯??
- ????????{??
- ????????printf("errno?is?%s\n",?strerror(errno));?//這里輸出"onnection?reset?by?peer"??
- ????????continue;??
- ????????}??
- ????????readbuffer[readsize]?=?'\0';???
- ????????tick?=?time(NULL);?//獲取時間??
- ????????????snprintf(timebuffer,?sizeof(timebuffer),?"time?:?%.24s\r\n",???
- ????????ctime(&tick));??
- ????????strcat(readbuffer,?timebuffer);??//時間與客戶數據連接到一起??
- ??????????
- ????????write(connfd,?readbuffer,?strlen(readbuffer));??//發送給客戶端??
- ????}??
- //??printf("close?the?connfd\n");??
- //??fflush(stdout);??
- ??
- ????close(connfd);??
- ????}??
- };??
- ??
- int?main(int?argc,?char?*argv[])??
- {??
- ????if(argc?!=?2)??
- ????{??
- ????printf("uasge?:?%s?port",?argv[0]);??
- ????exit(-1);??
- ????}??
- ????int?sockfd,?connfd;??
- ????struct?sockaddr_in?serv_addr,?cli_addr;??
- ????int?port?=?atoi(argv[1]);??
- ????//初始化sockaddr_in??
- ????serv_addr.sin_family?=?AF_INET;??
- ????serv_addr.sin_port?=?htons(port);??
- ????serv_addr.sin_addr.s_addr?=?htonl(INADDR_ANY);??//允許任何人連接??
- ????//創建套接字??
- ????sockfd?=?socket(AF_INET,?SOCK_STREAM,?0);??
- ????if(sockfd?<?0)??
- ????{??
- ????printf("socket?error'?n");??
- ????exit(-1);??
- ????}??
- ????//綁定??
- ????bind(sockfd,?(SSA?*)&serv_addr,?sizeof(serv_addr));??
- ????//監聽套接字??
- ????listen(sockfd,?6);??
- ????//創建線程池??
- ????threadpool<task>?pool(60,?100);??
- ????pool.start();??//開啟線程池??
- ????while(1)??
- ????{??
- ????socklen_t?len?=?sizeof(cli_addr);??
- ????connfd?=?accept(sockfd,?(SSA?*)&cli_addr,?&len);??//接受連接??
- ????task?*ta?=?new?task(connfd);???//新建任務??
- ????char?buf[20];??
- ????printf("IP?%s?conn\n",?inet_ntop(AF_INET,?&cli_addr.sin_addr,?buf,???
- ????????sizeof(buf)));??
- ????????while(!pool.append_task(ta))??//添加任務到任務隊列??
- ????????printf("loop\n");?//測試用??
- ????}??
- ????return?0;??
- }??
下面的是客戶端的代碼:
- #include?<stdio.h>??
- #include?<sys/socket.h>??
- #include?<arpa/inet.h>??
- #include?<string.h>??
- #include?<sys/types.h>??
- #include?<unistd.h>??
- #include?<netinet/in.h>??
- #include?<stdlib.h>??
- ??
- int?main(int?argc,?char?*argv[])??
- {??
- ????if(argc?!=?3)?//參數不對,退出??
- ????{??
- ????printf("usage:?%s?ip?port\n",?argv[0]);??
- ????exit(-1);??
- ????}??
- ????int?sockfd;??
- ????struct?sockaddr_in?serv_addr;??
- ????int?port?=?atoi(argv[2]);??//將字符串的端口轉換稱int??
- ????//初始化服務端的端口和IP地址??
- ????serv_addr.sin_family?=?AF_INET;??
- ????serv_addr.sin_port?=?htons(port);??//將主機字節序轉換稱網絡字節序??
- ????inet_pton(AF_INET,?argv[1],?&serv_addr.sin_addr);??
- ????//創建套接字??
- ????sockfd?=?socket(AF_INET,?SOCK_STREAM,?0);??
- ????//連接??
- ????connect(sockfd,?(struct?sockaddr?*)&serv_addr,???
- ????????sizeof(serv_addr));??
- ????char?buffer[50];??
- ????write(sockfd,?"hello\n",?6);??//寫數據??
- ????shutdown(sockfd,?SHUT_WR);??//解釋在下面??
- ????size_t?num?=?read(sockfd,?buffer,?sizeof(buffer));??//讀數據??
- ????buffer[num]?=?'\0';??
- ????printf("read:?%s\n",?buffer);??
- ????shutdown(sockfd,?SHUT_RD);??
- //????close(sockfd);??
- ????return?0;??
- }??
客戶端一開始我使用的是最后來個close的,就是注釋那部分,但是多個連接同時來的時候,服務端會出錯,具體的出錯信息是:Connection reset by peer,重新執行read之后,得到Hello的個數沒有少,也就是客戶端發送的個數。
然而我客戶端寫完數據,就關閉寫端,讀取完數據,再關閉讀端,就不會出現這樣的錯誤。
具體原因還不是很清楚,網上沒有查找到具體的答案。求大神來解答!!~~
==============================================
終于知道原因了,出錯的是在服務端的read函數,read返回-1,而在客戶端,發送完數據,就shutdown寫端,發送完數據,就會發送FIN包,服務端read返回0,因為read不止被調用一次,第一次讀取完數據之后,繼續讀取,可是客戶端沒有數據可讀,就會出錯,而提前關閉客戶端寫端,所以read那里的WHILE退出,就沒有了出錯的信息。
同時寫了兩個shell文件來測試:
- #!/bin/bash??
- ??
- for?i?in?`seq?2000`???
- do??
- ????./client.out?127.0.0.1?8989??
- done??
循環 執行2000次。
第二個shell文件:
- #!/bin/bash??
- ??
- ./loop.sh?>?file1?&??
- ./loop.sh?>?file2?&??
- ./loop.sh?>?file3?&??
- ./loop.sh?>?file4?&??
- ./loop.sh?>?file5?&??
- wait??
執行第二個shell文件
最終,耗時為:
- real????0m7.589s??
- user????0m0.460s??
- sys?0m1.944s??
而且五個File文件中,有Hello的行數數都為2000.
下一篇是實現一個簡單小型的web服務器。