日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

TCP 客户端和服务器端

發布時間:2023/11/30 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TCP 客户端和服务器端 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://blog.csdn.net/itcastcpp/article/details/39047265

前面幾篇中實現的client每次運行只能從命令行讀取一個字符串發給服務器,再從服務器收回來,現在我們把它改成交互式的,不斷從終端接受用戶輸入并和server交互。

?

[cpp]?view plain?copy
  • /*?client.c?*/??
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<unistd.h>??
  • #include?<netinet/in.h>??
  • #include?"wrap.h"??
  • ???
  • #define?MAXLINE?80??
  • #define?SERV_PORT?8000??
  • ???
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ?????????structsockaddr_in?servaddr;??
  • ?????????charbuf[MAXLINE];??
  • ?????????intsockfd,?n;??
  • ?????
  • ?????????sockfd=?Socket(AF_INET,?SOCK_STREAM,?0);??
  • ???
  • ?????????bzero(&servaddr,sizeof(servaddr));??
  • ?????????servaddr.sin_family=?AF_INET;??
  • ?????????inet_pton(AF_INET,"127.0.0.1",?&servaddr.sin_addr);??
  • ?????????servaddr.sin_port=?htons(SERV_PORT);??
  • ?????
  • ?????????Connect(sockfd,(struct?sockaddr?*)&servaddr,?sizeof(servaddr));??
  • ???
  • ?????????while(fgets(buf,?MAXLINE,?stdin)?!=?NULL)?{??
  • ???????????????????Write(sockfd,buf,?strlen(buf));??
  • ???????????????????n=?Read(sockfd,?buf,?MAXLINE);??
  • ???????????????????if(n?==?0)??
  • ????????????????????????????printf("theother?side?has?been?closed.\n");??
  • ???????????????????else??
  • ????????????????????????????Write(STDOUT_FILENO,buf,?n);??
  • ?????????}??
  • ???
  • ?????????Close(sockfd);??
  • ?????????return0;??
  • }??


  • 編譯并運行server和client,看看是否達到了你預想的結果。

    ?

    這時server仍在運行,但是client的運行結果并不正確。原因是什么呢?仔細查看server.c可以發現,server對每個請求只處理一次,應答后就關閉連接,client不能繼續使用這個連接發送數據。但是client下次循環時又調用write發數據給server,write調用只負責把數據交給TCP發送緩沖區就可以成功返回了,所以不會出錯,而server收到數據后應答一個RST段,client收到RST段后無法立刻通知應用層,只把這個狀態保存在TCP協議層。client下次循環又調用write發數據給server,由于TCP協議層已經處于RST狀態了,因此不會將數據發出,而是發一個SIGPIPE信號給應用層,SIGPIPE信號的缺省處理動作是終止程序,所以看到上面的現象。

    ?

    為了避免client異常退出,上面的代碼應該在判斷對方關閉了連接后break出循環,而不是繼續write。另外,有時候代碼中需要連續多次調用write,可能還來不及調用read得知對方已關閉了連接就被SIGPIPE信號終止掉了,這就需要在初始化時調用sigaction處理SIGPIPE信號,如果SIGPIPE信號沒有導致進程異常退出,write返回-1并且errno為EPIPE。

    ?

    另外,我們需要修改server,使它可以多次處理同一客戶端的請求。

    ?

    [cpp]?view plain?copy
  • /*?server.c?*/??
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<netinet/in.h>??
  • #include?"wrap.h"??
  • ???
  • #define?MAXLINE?80??
  • #define?SERV_PORT?8000??
  • ???
  • int?main(void)??
  • {??
  • ?????????structsockaddr_in?servaddr,?cliaddr;??
  • ?????????socklen_tcliaddr_len;??
  • ?????????intlistenfd,?connfd;??
  • ?????????charbuf[MAXLINE];??
  • ?????????charstr[INET_ADDRSTRLEN];??
  • ?????????inti,?n;??
  • ???
  • ?????????listenfd=?Socket(AF_INET,?SOCK_STREAM,?0);??
  • ???
  • ?????????bzero(&servaddr,sizeof(servaddr));??
  • ?????????servaddr.sin_family=?AF_INET;??
  • ?????????servaddr.sin_addr.s_addr=?htonl(INADDR_ANY);??
  • ?????????servaddr.sin_port=?htons(SERV_PORT);??
  • ?????
  • ?????????Bind(listenfd,(struct?sockaddr?*)&servaddr,?sizeof(servaddr));??
  • ???
  • ?????????Listen(listenfd,20);??
  • ???
  • ?????????printf("Acceptingconnections?...\n");??
  • ?????????while(1)?{??
  • ???????????????????cliaddr_len=?sizeof(cliaddr);??
  • ???????????????????connfd=?Accept(listenfd,??
  • ?????????????????????????????????????(structsockaddr?*)&cliaddr,?&cliaddr_len);??
  • ???????????????????while(1)?{??
  • ????????????????????????????n=?Read(connfd,?buf,?MAXLINE);??
  • ????????????????????????????if(n?==?0)?{??
  • ?????????????????????????????????????printf("theother?side?has?been?closed.\n");??
  • ?????????????????????????????????????break;??
  • ????????????????????????????}??
  • ????????????????????????????printf("receivedfrom?%s?at?PORT?%d\n",??
  • ???????????????????????????????????inet_ntop(AF_INET,&cliaddr.sin_addr,?str,?sizeof(str)),??
  • ???????????????????????????????????ntohs(cliaddr.sin_port));??
  • ?????
  • ????????????????????????????for(i?=?0;?i?<?n;?i++)??
  • ?????????????????????????????????????buf[i]=?toupper(buf[i]);??
  • ????????????????????????????Write(connfd,buf,?n);??
  • ???????????????????}??
  • ???????????????????Close(connfd);??
  • ?????????}??
  • }??

  • ?

    經過上面的修改后,客戶端和服務器可以進行多次交互了。

    ?

    前面幾篇中實現的client每次運行只能從命令行讀取一個字符串發給服務器,再從服務器收回來,現在我們把它改成交互式的,不斷從終端接受用戶輸入并和server交互。

    ?

    [cpp]?view plain?copy
  • /*?client.c?*/??
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<unistd.h>??
  • #include?<netinet/in.h>??
  • #include?"wrap.h"??
  • ???
  • #define?MAXLINE?80??
  • #define?SERV_PORT?8000??
  • ???
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ?????????structsockaddr_in?servaddr;??
  • ?????????charbuf[MAXLINE];??
  • ?????????intsockfd,?n;??
  • ?????
  • ?????????sockfd=?Socket(AF_INET,?SOCK_STREAM,?0);??
  • ???
  • ?????????bzero(&servaddr,sizeof(servaddr));??
  • ?????????servaddr.sin_family=?AF_INET;??
  • ?????????inet_pton(AF_INET,"127.0.0.1",?&servaddr.sin_addr);??
  • ?????????servaddr.sin_port=?htons(SERV_PORT);??
  • ?????
  • ?????????Connect(sockfd,(struct?sockaddr?*)&servaddr,?sizeof(servaddr));??
  • ???
  • ?????????while(fgets(buf,?MAXLINE,?stdin)?!=?NULL)?{??
  • ???????????????????Write(sockfd,buf,?strlen(buf));??
  • ???????????????????n=?Read(sockfd,?buf,?MAXLINE);??
  • ???????????????????if(n?==?0)??
  • ????????????????????????????printf("theother?side?has?been?closed.\n");??
  • ???????????????????else??
  • ????????????????????????????Write(STDOUT_FILENO,buf,?n);??
  • ?????????}??
  • ???
  • ?????????Close(sockfd);??
  • ?????????return0;??
  • }??


  • 編譯并運行server和client,看看是否達到了你預想的結果。

    ?

    這時server仍在運行,但是client的運行結果并不正確。原因是什么呢?仔細查看server.c可以發現,server對每個請求只處理一次,應答后就關閉連接,client不能繼續使用這個連接發送數據。但是client下次循環時又調用write發數據給server,write調用只負責把數據交給TCP發送緩沖區就可以成功返回了,所以不會出錯,而server收到數據后應答一個RST段,client收到RST段后無法立刻通知應用層,只把這個狀態保存在TCP協議層。client下次循環又調用write發數據給server,由于TCP協議層已經處于RST狀態了,因此不會將數據發出,而是發一個SIGPIPE信號給應用層,SIGPIPE信號的缺省處理動作是終止程序,所以看到上面的現象。

    ?

    為了避免client異常退出,上面的代碼應該在判斷對方關閉了連接后break出循環,而不是繼續write。另外,有時候代碼中需要連續多次調用write,可能還來不及調用read得知對方已關閉了連接就被SIGPIPE信號終止掉了,這就需要在初始化時調用sigaction處理SIGPIPE信號,如果SIGPIPE信號沒有導致進程異常退出,write返回-1并且errno為EPIPE。

    ?

    另外,我們需要修改server,使它可以多次處理同一客戶端的請求。

    ?

    [cpp]?view plain?copy
  • /*?server.c?*/??
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<netinet/in.h>??
  • #include?"wrap.h"??
  • ???
  • #define?MAXLINE?80??
  • #define?SERV_PORT?8000??
  • ???
  • int?main(void)??
  • {??
  • ?????????structsockaddr_in?servaddr,?cliaddr;??
  • ?????????socklen_tcliaddr_len;??
  • ?????????intlistenfd,?connfd;??
  • ?????????charbuf[MAXLINE];??
  • ?????????charstr[INET_ADDRSTRLEN];??
  • ?????????inti,?n;??
  • ???
  • ?????????listenfd=?Socket(AF_INET,?SOCK_STREAM,?0);??
  • ???
  • ?????????bzero(&servaddr,sizeof(servaddr));??
  • ?????????servaddr.sin_family=?AF_INET;??
  • ?????????servaddr.sin_addr.s_addr=?htonl(INADDR_ANY);??
  • ?????????servaddr.sin_port=?htons(SERV_PORT);??
  • ?????
  • ?????????Bind(listenfd,(struct?sockaddr?*)&servaddr,?sizeof(servaddr));??
  • ???
  • ?????????Listen(listenfd,20);??
  • ???
  • ?????????printf("Acceptingconnections?...\n");??
  • ?????????while(1)?{??
  • ???????????????????cliaddr_len=?sizeof(cliaddr);??
  • ???????????????????connfd=?Accept(listenfd,??
  • ?????????????????????????????????????(structsockaddr?*)&cliaddr,?&cliaddr_len);??
  • ???????????????????while(1)?{??
  • ????????????????????????????n=?Read(connfd,?buf,?MAXLINE);??
  • ????????????????????????????if(n?==?0)?{??
  • ?????????????????????????????????????printf("theother?side?has?been?closed.\n");??
  • ?????????????????????????????????????break;??
  • ????????????????????????????}??
  • ????????????????????????????printf("receivedfrom?%s?at?PORT?%d\n",??
  • ???????????????????????????????????inet_ntop(AF_INET,&cliaddr.sin_addr,?str,?sizeof(str)),??
  • ???????????????????????????????????ntohs(cliaddr.sin_port));??
  • ?????
  • ????????????????????????????for(i?=?0;?i?<?n;?i++)??
  • ?????????????????????????????????????buf[i]=?toupper(buf[i]);??
  • ????????????????????????????Write(connfd,buf,?n);??
  • ???????????????????}??
  • ???????????????????Close(connfd);??
  • ?????????}??
  • }??

  • ?

    經過上面的修改后,客戶端和服務器可以進行多次交互了。

    ?

    總結

    以上是生活随笔為你收集整理的TCP 客户端和服务器端的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。