电竞比分网-中国电竞赛事及体育赛事平台

分享

[精通WindowsSocket網(wǎng)絡(luò)開(kāi)發(fā)

 firefox_zyw 2013-07-11

[精通WindowsSocket網(wǎng)絡(luò)開(kāi)發(fā)-基于VC++實(shí)現(xiàn)]第三章——WindowsSockets基礎(chǔ)—TCP,UDP程序

分類: 網(wǎng)絡(luò)編程 3514人閱讀 評(píng)論(7) 收藏 舉報(bào)

目錄(?)[+]

TCP程序

 

TCPServer

  1. // TCPServer.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。   
  2. //接收客戶的發(fā)來(lái)的"MyTCP"   
  3. #include <stdio.h>   
  4. #include <WinSock2.h>   
  5. #pragma  comment(lib,"ws2_32.lib")   
  6. #define  BUF_SIZE 64   
  7. void main()  
  8. {  
  9.     WSADATA wsd;  
  10.     if (WSAStartup(MAKEWORD(2,2),&wsd) != 0)//初始化套接字動(dòng)態(tài)庫(kù)   
  11.     {  
  12.         printf("WSAStartup() failed! erron=%d\n",GetLastError());  
  13.         return;  
  14.     }  
  15.     SOCKET sServ;  
  16.     if ((sServ=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)//創(chuàng)建套接字   
  17.     {  
  18.         printf("socket() failed! errno=%d\n",WSAGetLastError());  
  19.         WSACleanup();  
  20.         return;  
  21.     }  
  22.   
  23.     //綁定服務(wù)器地址   
  24.     SOCKADDR_IN addrServ;  
  25.     addrServ.sin_family=AF_INET;  
  26.     addrServ.sin_addr.S_un.S_addr=INADDR_ANY;  
  27.     addrServ.sin_port=htons(5000);  
  28.     if (bind(sServ,(SOCKADDR*)&addrServ,sizeof(addrServ)) == SOCKET_ERROR)  
  29.     {  
  30.         printf("bind() failed!errno=%d\n",WSAGetLastError());  
  31.         closesocket(sServ);//關(guān)閉套接字   
  32.         WSACleanup();//釋放套接字資源   
  33.         return;  
  34.     }  
  35.   
  36.     if (listen(sServ,2) == SOCKET_ERROR)//開(kāi)始監(jiān)聽(tīng)   
  37.     {  
  38.         printf("listen() failed! errno=%\n",WSAGetLastError());  
  39.         closesocket(sServ);  
  40.         WSACleanup();  
  41.         return;  
  42.     }  
  43.   
  44.     SOCKADDR_IN addrClient;  
  45.     SOCKET sClient;  
  46.     int len=sizeof(addrClient);  
  47.     if ((sClient=accept(sServ,(SOCKADDR*)&addrClient,&len)) == INVALID_SOCKET)//接收客戶端連接   
  48.     {  
  49.         printf("accept() failed! error=%d\n",WSAGetLastError());  
  50.         closesocket(sServ);  
  51.         WSACleanup();  
  52.         return;  
  53.     }  
  54.   
  55.     //接收客戶端數(shù)據(jù)   
  56.     char buf[BUF_SIZE];       
  57.     ZeroMemory(buf,BUF_SIZE);  
  58.     if (recv(sClient,buf,BUF_SIZE,0) == SOCKET_ERROR)  
  59.     {  
  60.         printf("recv() failed! error=%d\n",WSAGetLastError());  
  61.         closesocket(sClient);  
  62.         closesocket(sServ);  
  63.         WSACleanup();  
  64.         return;  
  65.     }  
  66.     printf("%s\n",buf);//輸出“MyTCP”   
  67.     closesocket(sClient);  
  68.     closesocket(sServ);  
  69.     WSACleanup();  
  70.     system("pause");  
  71.     return;  
  72. }  
  73. //相對(duì)完整的http://blog.csdn.net/ouyangshima/article/details/8932334   
  74. /* 
  75. TCP編程的服務(wù)器端一般步驟是 
  76. 1.創(chuàng)建一個(gè)socket,用函數(shù)socket(); 
  77. 2.設(shè)置socket屬性,用函數(shù)setsockopt();  //可選 
  78. 3.綁定IP地址,端口等信息到socket上,用函數(shù)bind();    
  79. 4.開(kāi)啟監(jiān)聽(tīng),用函數(shù)listen(); 
  80. 5.接收客戶端上的來(lái)的連接,用函數(shù)accept(); 
  81. 6.收到數(shù)據(jù)用send()和recv(),或者read()和write(); 
  82. 7.關(guān)閉網(wǎng)絡(luò)連接 
  83. 8.關(guān)閉監(jiān)聽(tīng) 
  84. 服務(wù)器端 socket-->bind-->listen-->accept  
  85. */  

TCPClient 

  1. // TCPClient.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。   
  2. //功能:向服務(wù)器端發(fā)送“MyTCP”   
  3. #include <stdio.h>   
  4. #include <WinSock2.h>   
  5. #pragma comment(lib,"ws2_32.lib")   
  6. #define BUF_SIZE 64   
  7.  void main()  
  8.  {  
  9.      WSADATA wsd;  
  10.      if (WSAStartup(MAKEWORD(2,2),&wsd) != 0)//初始化套接字動(dòng)態(tài)庫(kù)   
  11.      {  
  12.          printf("WSAStartup() failed! erron=%d\n",GetLastError());  
  13.          return;  
  14.      }  
  15.   
  16.      SOCKET sHost;//服務(wù)器套接字   
  17.      if ((sHost=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)//創(chuàng)建套接字   
  18.      {  
  19.          printf("socket() failed! errno=%d\n",WSAGetLastError());  
  20.          WSACleanup();//釋放套接字資源   
  21.          return;  
  22.      }  
  23.       
  24.      //設(shè)置服務(wù)器地址   
  25.      SOCKADDR_IN servAddr;  
  26.      servAddr.sin_family=AF_INET;  
  27.      servAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");  
  28.      servAddr.sin_port=htons(5000);  
  29.      if (connect(sHost,(SOCKADDR*)&servAddr,sizeof(servAddr)) == SOCKET_ERROR)//連接套接字   
  30.      {  
  31.          printf("connect() failed! errno=%d\n",WSAGetLastError());  
  32.          closesocket(sHost);//關(guān)閉套接字   
  33.          WSACleanup();  
  34.          return;  
  35.      }  
  36.   
  37.      //向服務(wù)器發(fā)送數(shù)據(jù)   
  38.      char buf[BUF_SIZE];  
  39.      ZeroMemory(buf,BUF_SIZE);  
  40.      strcpy(buf,"MyTCP");  
  41.      if (send(sHost,buf,strlen(buf),0) == SOCKET_ERROR)  
  42.      {  
  43.          printf("send() failed! erron=%d\n",WSAGetLastError());  
  44.          closesocket(sHost);  
  45.          WSACleanup();  
  46.          return;  
  47.      }  
  48.      //退出   
  49.      closesocket(sHost);  
  50.      WSACleanup();  
  51.      system("pause");  
  52.      return;  
  53.  }  
  54.  //相對(duì)完整的http://blog.csdn.net/ouyangshima/article/details/8922575   
  55.  /* 
  56.  TCP編程的客戶端一般步驟是 
  57.  1.創(chuàng)建一個(gè)socket,用函數(shù)sockect(); 
  58.  2.設(shè)置socket屬性,用函數(shù)setsockopt();  //可選 
  59.  3.綁定IP地址,端口等信息到socket上,用函數(shù)bind();  //可選 
  60.  4.設(shè)置要連接的對(duì)方的IP地址和端口等屬性; 
  61.  5.連接服務(wù)器,用函數(shù)connect(); 
  62.  6.收到數(shù)據(jù),用函數(shù)send()和recv()或者read()和write(); 
  63.  7.關(guān)閉網(wǎng)絡(luò)連接 
  64.  客戶端 socket-->connect 
  65.  */  

TCP API 

  1. /* 
  2. 1.WSAStartup()函數(shù) 
  3. WSAStartup():功能是加載ws2_32.dll等socket程序運(yùn)行環(huán)境的動(dòng)態(tài)庫(kù)(DLL)。在程序初始化后,socket程序運(yùn)行所依賴的動(dòng)態(tài)鏈接庫(kù)不一定已經(jīng)加載,WSAStartup保證了Socket動(dòng)態(tài)鏈接庫(kù)的加載。 
  4. int WSAStartup(_in Word wVersionRequested,_out LPWSDATA lpWSAData); 
  5. wVersionRequested:是Socket程序庫(kù)的版本。高字節(jié)指定所需要庫(kù)文件的副版本,低字節(jié)指定主版本。在程序中可以使用MAKEWORD(X,Y)方便指定參數(shù),其中X是指高位字節(jié),Y是指低位字節(jié)。一般使用MAKEWORD(2,2)宏 
  6. lpWSAData:輸出參數(shù),指向WSADATA結(jié)構(gòu)的指針,用于返回scoket庫(kù)初始化的信息 
  7. 返回值:0表示成功, 
  8. WSACleanup():與WSAStartup()的功能相反,WSACleanup釋放ws2_32.dll庫(kù)。 
  9. WSADATA wsaData;   
  10. LPVOID recvbuf;   
  11. if (WSAStartup(MAKEWORD(2,2),&wsaData) != NO_ERROR)   
  12. {   
  13. printf("Error at WSAStartup()\n");   
  14.  
  15. if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wVersion) != 2)//檢查返回的DLL是否為2.2 
  16. { 
  17.       //沒(méi)有找到可用的DLL 
  18.       WSACleanup(); 
  19.       return; 
  20. } 
  21.  
  22. 2.socket()函數(shù) 
  23. SOCKET socket( int af, int type, int protocol ); 等價(jià)于WSASocket() 
  24. 參數(shù):int af:協(xié)議的地址家族(AF_UNIX,AF_INET等),AF_UNIX只能夠用于單一的Unix系統(tǒng)進(jìn)程間的通信,而AF_INET是針對(duì)Internet的,因此可以允許遠(yuǎn)程——本機(jī)之間的通信。AF:Address families(地址協(xié)議族)。協(xié)議族決定了socket的地址類型,在通信中必須采用對(duì)應(yīng)的地址,如AF_INET決定了要用ipv4地址(32位的)與端口號(hào)(16位的)的組合、AF_UNIX決定了要用一個(gè)絕對(duì)路徑名作為地址。創(chuàng)建TCP或者UDP套接字時(shí),該參數(shù)為AF_INET 
  25. int type:協(xié)議的套接字類型:有SOCK_STREAM(TCP),SOCK_DGRAM(UDP),SOCK_RAM 3種 
  26. int protocol:指定協(xié)議(有IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它們分別對(duì)應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議、STCP傳輸協(xié)議、TIPC傳輸協(xié)議),由于我們指定了type,所以這個(gè)地方我們一般只要用0來(lái)代替就可以了 
  27. 返回值:若成功返回SOCKET對(duì)象標(biāo)識(shí),SOCKET就是unsigned int;如失敗,則返回INVALID_SOCKET,調(diào)用WSAGetLastError()可得知原因,所有WinSocket的函數(shù)都可以使用這個(gè)函數(shù)來(lái)獲取失敗的原因。 
  28. 注意:并不是上面的type和protocol可以隨意組合的,如SOCK_STREAM不可以跟IPPROTO_UDP組合。當(dāng)protocol為0時(shí),會(huì)自動(dòng)選擇type類型對(duì)應(yīng)的默認(rèn)協(xié)議。 
  29. 當(dāng)我們調(diào)用socket創(chuàng)建一個(gè)socket時(shí),返回的socket描述字它存在于協(xié)議族(address family,AF_XXX)空間中,但沒(méi)有一個(gè)具體的地址。如果想要給它賦值一個(gè)地址,就必須調(diào)用bind()函數(shù),否則就當(dāng)調(diào)用connect()、listen()時(shí)系統(tǒng)會(huì)自動(dòng)隨機(jī)分配一個(gè)端口。 
  30.  
  31. 3.bind()函數(shù) 
  32. 當(dāng)我們調(diào)用socket創(chuàng)建一個(gè)socket時(shí),返回的socket描述字它存在于協(xié)議族(address family,AF_XXX)空間中,但沒(méi)有一個(gè)具體的地址。如果想要給它賦值一個(gè)地址,就必須調(diào)用bind()函數(shù),否則就當(dāng)調(diào)用connect()、listen()時(shí)系統(tǒng)會(huì)自動(dòng)隨機(jī)分配一個(gè)端口。 
  33. bind()函數(shù)把一個(gè)地址族中的特定地址賦給socket。例如,對(duì)應(yīng)AF_INET、AF_INET6就是把一個(gè)ipv4或ipv6地址和端口號(hào)組合賦給socket。 
  34. int bind(SOCKET s,sockaddr * name,int namelen); 
  35. 參 數(shù): s:Socket對(duì)象名,它通過(guò)socket()創(chuàng)建了,唯一標(biāo)識(shí)一個(gè)socket 
  36. name:地址,服務(wù)器地址信息名稱(包含信息有:地址協(xié)議族,服務(wù)器本機(jī)的IP,要監(jiān)聽(tīng)的端口) 
  37. namelen:sockaddr的結(jié)構(gòu)長(zhǎng)度 
  38. 返回值:成功返回0,否則返回SOCKET_ERROR 
  39. 通常服務(wù)器在啟動(dòng)的時(shí)候會(huì)綁定一個(gè)眾說(shuō)周知的地址(如ip地址+端口號(hào)),用于提供服務(wù),客戶就可以通過(guò)它(ip+port)來(lái)連接服務(wù)器;而客戶端就不用指定,有系統(tǒng)自動(dòng)分配一個(gè)端口號(hào)和自身的ip地址組合。這就是為什么通常服務(wù)器端在listen之前會(huì)調(diào)用bind(),而客戶端就不用調(diào)用,而是在connect()時(shí)由系統(tǒng)隨機(jī)生成一個(gè)。 
  40. SOCKET s; 
  41. SOCKADDR_IN servAddr; 
  42. //定義服務(wù)器地址 
  43. servAddr.sin_family=AF_INET; 
  44. servAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//如果程序不關(guān)心分配給它的地址,則可將地址設(shè)置為INADDR_ANY,可以使用任意網(wǎng)絡(luò)接口。 
  45. servAddr.sin_port=htons(2222); 
  46. if (bind(s,(SOCKADDR*)&servAddr,sizeof(servAddr)) == SOCKET_ERROR)//綁定服務(wù)器地址 
  47.  
  48.   //綁定套接字失敗 
  49. } 
  50.  
  51. 4.listen()函數(shù) 
  52. int listen(SOCKET s,int backlog);將套接字設(shè)置為監(jiān)聽(tīng)模式 
  53. 參 數(shù): s:一個(gè)已綁定的套接字 
  54. backlog:指定等待連接的最大隊(duì)列長(zhǎng)度(一般2~4,用SOMAXCONN則有系統(tǒng)確定)。socket可以排隊(duì)的最大連接個(gè)數(shù),不是最多可以連接幾個(gè)客戶端。更具體些:TCP模塊允許的已完成三次握手過(guò)程(TCP模塊完成)但還沒(méi)來(lái)得及被應(yīng)用程序accep()的最大連接數(shù)。eg:listen(socketID,3);如果有4個(gè)客戶端同時(shí)向服務(wù)器發(fā)出請(qǐng)求,那么前3個(gè)連接會(huì)被放到等待處理的隊(duì)列中,以便服務(wù)器依次為他們服務(wù),而第4個(gè)連接將會(huì)造成WSAECONNREFUSED錯(cuò)誤。當(dāng)服務(wù)器接受了一個(gè)連接請(qǐng)求時(shí),這個(gè)請(qǐng)求就從隊(duì)列中刪除。 
  55. 返回值:成功返回0,否則返回SOCKET_ERROR 
  56. socket()函數(shù)創(chuàng)建的socket默認(rèn)是一個(gè)主動(dòng)類型的,listen()函數(shù)則將主動(dòng)連接套接口socket變?yōu)楸粍?dòng)連接套接口,使得這個(gè)進(jìn)程可以接受其他進(jìn)程的請(qǐng)求(客戶的連接請(qǐng)求),從而成為一個(gè)服務(wù)器進(jìn)程。 
  57.  
  58. 5.accept()函數(shù) 
  59. SOCKET accept(SOCKET s,_output struct sockaddr * addr,_output int * addrlen); 
  60. 參數(shù):s:監(jiān)聽(tīng)套接字, 
  61. addr:存放來(lái)連接的客戶端的地址和端口,(若客戶端使用了bind()來(lái)綁定客戶端本地的IP和Port,則服務(wù)器端會(huì)得到客戶端bind的端口,而不是服務(wù)器端自動(dòng)分配的端口)。當(dāng)我們調(diào)用socket()創(chuàng)建一個(gè)socket時(shí),返回的socket描述字它存在于協(xié)議族(address family,AF_XXX)空間中,但沒(méi)有一個(gè)具體的地址。如果想要給它賦值一個(gè)地址,就必須調(diào)用bind()函數(shù),否則就當(dāng)調(diào)用connect()、listen()時(shí)系統(tǒng)會(huì)自動(dòng)隨機(jī)分配一個(gè)端口。若對(duì)客戶端的IP地址不感興趣,則可以設(shè)為NULL 
  62. addrlen:返回addr結(jié)構(gòu)的長(zhǎng)度,sizeof(SOCKADDR_IN),當(dāng)addr為NULL時(shí),addrlen則可以為NULL 
  63. 返回值:功返回一個(gè)新產(chǎn)生的Socket對(duì)象,否則返回INVALID_SOCKET 
  64. accept()默認(rèn)會(huì)阻塞進(jìn)程(所以需要一個(gè)單獨(dú)的線程來(lái)等待客戶端的連接),直到有一個(gè)客戶連接建立后返回,它返回的是一個(gè)新可用的套接字,這個(gè)套接字就是連接套接字。 
  65. 監(jiān)聽(tīng)套接字:監(jiān)聽(tīng)套接字正如accept()的參數(shù)sockfd,它就是監(jiān)聽(tīng)套接字,在調(diào)用listen()函數(shù)之后。 
  66. 連接套接字:一個(gè)套接字會(huì)從主動(dòng)連接的套接字變?yōu)橐粋€(gè)監(jiān)聽(tīng)套接字;而accept()返回的是已連接socket描述字(一個(gè)連接套接字),它代表一個(gè)網(wǎng)絡(luò)已經(jīng)存在的點(diǎn)點(diǎn)連接。 
  67. 一個(gè)服務(wù)器通常僅僅只創(chuàng)建一個(gè)監(jiān)聽(tīng)socket描述符,它在該服務(wù)器的生命周期內(nèi)一直存在。內(nèi)核為每個(gè)有服務(wù)器進(jìn)程接收的客戶端連接創(chuàng)建了一個(gè)已連接的socket描述符,當(dāng)服務(wù)器完成了對(duì)某個(gè)客戶的服務(wù)后,相應(yīng)的已連接socket描述符就被關(guān)閉。 
  68. 連接套接字并沒(méi)有占有新的端口與客戶端通信,依然使用的是監(jiān)聽(tīng)套接字一樣的端口號(hào)。 
  69.  
  70. 6.recv()函數(shù) 
  71. int recv( SOCKET s, char FAR *buf, int len, int flags );等級(jí)與WSARecv() 
  72. 參數(shù):s:Socket 的識(shí)別碼 
  73. buf:接收數(shù)據(jù)緩沖區(qū) 
  74. len:緩沖區(qū)的長(zhǎng)度 
  75. flags:該參數(shù)影響該函數(shù)的行為,可以設(shè)為 0(表示無(wú)特殊行為),MSG_PEEK(會(huì)使有用的數(shù)據(jù)被復(fù)制到接收緩沖區(qū)內(nèi),但沒(méi)有從系統(tǒng)緩沖區(qū)中將其刪除),MSG_OOB(表示處理帶外數(shù)據(jù)) 
  76. 返回值:若成功則返回接收資料的長(zhǎng)度,否則返回SOCKET_ERROR 
  77.  
  78. 7.send()函數(shù) 
  79. int send( SOCKET s, const char FAR *buf,int len, int flags );等價(jià)于WSASend() 
  80. 參數(shù):s:Socket 的識(shí)別碼 
  81. buf:存放要傳送數(shù)據(jù)的暫存區(qū) 
  82. len:發(fā)送數(shù)據(jù)的長(zhǎng)度 
  83. flags:該參數(shù)影響該函數(shù)的行為,可以設(shè)為 0(表示無(wú)特殊行為),MSG_DONTROUTE(標(biāo)志要求傳輸層不要將數(shù)據(jù)路由出去),MSG_OOB(表示該數(shù)據(jù)被帶外發(fā)送) 
  84. 返回值:若成功則返回發(fā)送的資料的長(zhǎng)度,否則返回SOCKET_ERROR 
  85.  
  86. 8.closesocket()函數(shù) 
  87. int closesocket(SOCKET s);關(guān)閉套接字,釋放所占資源 
  88. 返回值:成功返回0,否則返回SOCKET_ERROR 
  89. 9.shutdown()函數(shù) 
  90. int shutdown(SOCKET s, int how);用于通知對(duì)方不再發(fā)送數(shù)據(jù),或者不再接收數(shù)據(jù),或者既不發(fā)送也不接收數(shù)據(jù) 
  91. 參數(shù):s:套接字 
  92. how:參數(shù)為SD_RECEIVE(表示不允許再調(diào)用接收數(shù)據(jù)函數(shù));SE_SEND(表示不允許再調(diào)用發(fā)送數(shù)據(jù)函數(shù));SD_BOTH(表示既不允許調(diào)用發(fā)送數(shù)據(jù)函數(shù)也不允許調(diào)用接收數(shù)據(jù)函數(shù)); 
  93. 返回值:成功返回0,否則返回-1 
  94.  
  95. 10.connect()函數(shù) 
  96. int connect(SOCKET s,const struct sockaddr FAR * name,int namelen); 
  97. 參數(shù):s:socket的標(biāo)識(shí)碼 
  98. name:存儲(chǔ)服務(wù)器的連接信息(協(xié)議族,服務(wù)器的ip,端口),服務(wù)器地址; 
  99. namelen:sockaddr結(jié)構(gòu)的長(zhǎng)度 
  100. 返回值:成功返回0,失敗返回SOCKET_ERROR 
  101.  
  102. 11.字節(jié)轉(zhuǎn)換函數(shù)  
  103. 在網(wǎng)絡(luò)上面有著許多類型的機(jī)器,這些機(jī)器在表示數(shù)據(jù)的字節(jié)順序是不同的,比如i386芯片是低字節(jié)在內(nèi)存地址的低端,高字節(jié)在高端,而alpha芯片卻相反.為了統(tǒng)一起來(lái),則有專門的字節(jié)轉(zhuǎn)換函數(shù).  
  104. unsigned long int htonl(unsigned long int hostlong)  
  105. unsigned short int htons(unisgned short int hostshort)  
  106. unsigned long int ntohl(unsigned long int netlong)  
  107. unsigned short int ntohs(unsigned short int netshort) 
  108. 在這四個(gè)轉(zhuǎn)換函數(shù)中,h代表host, n代表 network.s代表short l代表long 
  109. 第一個(gè)函數(shù)的意義是將本機(jī)器上的long數(shù)據(jù)轉(zhuǎn)化為網(wǎng)絡(luò)上的long.其他幾個(gè)函數(shù)的意義也差不多 
  110.  
  111. 12.地址結(jié)構(gòu)說(shuō)明 
  112. typedef struct sockaddr_in 
  113. { 
  114. short sin_family;//由于我們主要使用Internet,所以一般為AF_INET 
  115. u_short sin_port;//16位端口號(hào),網(wǎng)絡(luò)字節(jié)順序 
  116. struct in_addr sin_addr;//32位IP地址,網(wǎng)絡(luò)字節(jié)順序 
  117. char sin_zero[8];//保留 
  118. }SOCKADDR_IN; 
  119. struct in_addr  // Internet address.  
  120. {   
  121. uint32_t       s_addr;     // address in network byte order 
  122. }; 
  123. //sin_:socket address internet 
  124. struct sockaddr是通用的套接字地址,而struct sockaddr_in則是internet環(huán)境下套接字的地址形式,二者長(zhǎng)度一樣,都是16個(gè)字節(jié)。二者是并列結(jié)構(gòu),指向sockaddr_in結(jié)構(gòu)的指針也可以指向sockaddr。一般情況下,需要把sockaddr_in結(jié)構(gòu)強(qiáng)制轉(zhuǎn)換成sockaddr結(jié)構(gòu)再傳入系統(tǒng)調(diào)用函數(shù)中。  
  125. */  

UDP程序

 

無(wú)連接協(xié)議的套接字調(diào)用時(shí)序

UDPServer

  1. // UDPServer.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。   
  2. //功能:接收客戶端發(fā)來(lái)的"MyUDP"   
  3. #include <stdio.h>   
  4. #include <WinSock2.h>   
  5. #pragma comment(lib,"ws2_32.lib")   
  6. #define BUF_SIZE 64   
  7. void main()  
  8. {  
  9.     WSADATA wsd;  
  10.     if (WSAStartup(MAKEWORD(2,2),&wsd) != 0)//初始化套接字動(dòng)態(tài)庫(kù)   
  11.     {  
  12.         printf("WSAStartup failed,errno=%d\n",GetLastError());  
  13.         return;  
  14.     }  
  15.     SOCKET sockServ;  
  16.     if ((sockServ=socket(AF_INET,SOCK_DGRAM,0)) == INVALID_SOCKET)//創(chuàng)建套接字   
  17.     {  
  18.         printf("socket() failed,errno=%d\n",WSAGetLastError());  
  19.         WSACleanup();//釋放套接字資源   
  20.         return;  
  21.     }  
  22.   
  23.     int nBufLen;//接收數(shù)據(jù)緩沖區(qū)大小   
  24.     int nOptLen=sizeof(nBufLen);  
  25.     if (getsockopt(sockServ,SOL_SOCKET,SO_RCVBUF,(char*)&nBufLen,&nOptLen) == SOCKET_ERROR)//獲取接收數(shù)據(jù)緩沖區(qū)大小   
  26.     {  
  27.         printf("getsockopt() failed,errno=%d\n",WSAGetLastError());  
  28.     }  
  29.       
  30.     nBufLen *=10;//設(shè)置接收數(shù)據(jù)緩沖區(qū)為原來(lái)的10倍   
  31.     if (setsockopt(sockServ,SOL_SOCKET,SO_RCVBUF,(char*)&nBufLen,nOptLen) == SOCKET_ERROR)  
  32.     {  
  33.         printf("setsockopt() failed,errno=%d\n",WSAGetLastError());  
  34.     }  
  35.       
  36.     int newRcvBuf;//檢查設(shè)置系統(tǒng)接收數(shù)據(jù)緩沖區(qū)是否成功   
  37.     if (getsockopt(sockServ,SOL_SOCKET,SO_RCVBUF,(char*)&newRcvBuf,&nOptLen) == SOCKET_ERROR)  
  38.     {  
  39.         printf("second getsockopt() failed,errno=%d\n",WSAGetLastError());  
  40.     }  
  41.     if (newRcvBuf != nBufLen)  
  42.     {  
  43.         printf("set bufLen size=size*10 failed\n");  
  44.     }  
  45.       
  46.     //設(shè)置服務(wù)器地址   
  47.     SOCKADDR_IN addrServ;  
  48.     addrServ.sin_family=AF_INET;  
  49.     addrServ.sin_addr.s_addr=INADDR_ANY;  
  50.     addrServ.sin_port=htons(5000);  
  51.     if (bind(sockServ,(SOCKADDR*)&addrServ,sizeof(addrServ)) == SOCKET_ERROR)//綁定   
  52.     {  
  53.         printf("bind() failed,errno=%d\n",WSAGetLastError());  
  54.         closesocket(sockServ);  
  55.         WSACleanup();  
  56.         return;  
  57.     }  
  58.   
  59.     //接收數(shù)據(jù)   
  60.     SOCKADDR_IN addrClient;  
  61.     int addrClientLen=sizeof(addrClient);  
  62.     char buf[BUF_SIZE];  
  63.     ZeroMemory(buf,BUF_SIZE);  
  64.     if (recvfrom(sockServ,buf,BUF_SIZE,0,(SOCKADDR*)&addrClient,&addrClientLen) == SOCKET_ERROR)  
  65.     {  
  66.         printf("recvfrom() failed,errno=%d\n",WSAGetLastError());  
  67.         closesocket(sockServ);//關(guān)閉套接字   
  68.         WSACleanup();  
  69.         return;  
  70.     }  
  71.       
  72.     printf("%s\n",buf);//輸出 MyUDP   
  73.     closesocket(sockServ);  
  74.     WSACleanup();  
  75.     system("pause");  
  76.     return;  
  77. }  
  78. /* 
  79. UDP編程的服務(wù)器一般步驟是 
  80. 1.創(chuàng)建一個(gè)socket,用函數(shù)socket(); 
  81. 2.設(shè)置socket屬性,用函數(shù)setsockopt(); //可選 
  82. 3.綁定IP地址,端口燈屬性到socket上,用函數(shù)bind(); 
  83. 4.循環(huán)接收數(shù)據(jù),用函數(shù)recvfrom(); 
  84. 5.關(guān)閉網(wǎng)絡(luò)連接; 
  85. */  

UDPClient 

  1. // UDPClient.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。   
  2. //功能:向服務(wù)器端發(fā)送"MyUDP"   
  3. #include <stdio.h>   
  4. #include <WinSock2.h>   
  5. #pragma comment(lib,"ws2_32.lib")   
  6. #define BUF_SIZE 64   
  7. void main()  
  8. {  
  9.     WSADATA wsd;  
  10.     if (WSAStartup(MAKEWORD(2,2),&wsd) != 0)//初始化套接字動(dòng)態(tài)庫(kù)   
  11.     {  
  12.         printf("WSAStartup() failed,errno=%d\n",GetLastError());  
  13.         return;  
  14.     }  
  15.     SOCKET sClient;  
  16.     if ((sClient=socket(AF_INET,SOCK_DGRAM,0)) == INVALID_SOCKET)//創(chuàng)建套接字   
  17.     {  
  18.         printf("socket() failed,errno=%d\n",WSAGetLastError());  
  19.         WSACleanup();//釋放套接字資源   
  20.         return;  
  21.     }  
  22.     char buf[BUF_SIZE];  
  23.     ZeroMemory(buf,BUF_SIZE);  
  24.     strcpy(buf,"MyUDP");  
  25.   
  26.     //服務(wù)器地址   
  27.     SOCKADDR_IN addrServ;  
  28.     int addrServLen=sizeof(addrServ);  
  29.     addrServ.sin_family=AF_INET;  
  30.     addrServ.sin_addr.s_addr=inet_addr("127.0.0.1");  
  31.     addrServ.sin_port=htons(5000);  
  32.     if (sendto(sClient,buf,BUF_SIZE,0,(SOCKADDR*)&addrServ,addrServLen) == SOCKET_ERROR)//發(fā)送數(shù)據(jù)   
  33.     {  
  34.         printf("sendto() failed,errno=%d\n",WSAGetLastError());  
  35.         closesocket(sClient);//關(guān)閉套接字   
  36.         WSACleanup();  
  37.         return;  
  38.     }  
  39.     closesocket(sClient);  
  40.     WSACleanup();  
  41.     system("pause");  
  42.     return;  
  43. }  
  44. /* 
  45. UDP編程的客戶端的一般步驟是 
  46. 1.創(chuàng)建一個(gè)socket,用函數(shù)socket(); 
  47. 2.設(shè)置socket屬性,用函數(shù)setsockopt();  //可選 
  48. 3.綁定IP地址,端口等信息到socket上,用函數(shù)bing(); //可選 
  49. 4.設(shè)置對(duì)方的IP地址和端口等屬性; 
  50. 5.發(fā)送數(shù)據(jù),用sendto(); 
  51. 6.關(guān)閉網(wǎng)絡(luò)連接; 
  52. */  

UDP API 

  1. /* 
  2. 1.recvfrom()函數(shù) 
  3. int recvfrom(SOCKET s,char FAR* buf,int len,int flags,struct sockaddr FAR* from,int FAR* fromlen);用于接收數(shù)據(jù),并且返回發(fā)送數(shù)據(jù)主機(jī)地址 
  4. buf:接收數(shù)據(jù)緩沖區(qū) 
  5. len:接收數(shù)據(jù)緩沖區(qū)的大小 
  6. flags:該參數(shù)影響recvfrom()函數(shù)的行為。參數(shù)可以為0(表示無(wú)特殊行為);MSG_PEEK(會(huì)使有用的數(shù)據(jù)被復(fù)制到接收緩沖區(qū)內(nèi),但沒(méi)有從系統(tǒng)緩沖區(qū)中將其刪除);MSG_OOB(表示處理帶外數(shù)據(jù)); 
  7. from:該參數(shù)返回發(fā)送數(shù)據(jù)主機(jī)的地址 
  8. fromlen:地址長(zhǎng)度 
  9. 返回值:成功返回接收數(shù)據(jù)的字節(jié)數(shù),否則返回SOCKET_ERROR 
  10.  
  11. 2.sendto()函數(shù) 
  12. int sendto(SOCKET s,const char FAR* buf,int len,int flags,const struct sockaddr FAR* to,int tolen);//發(fā)送數(shù)據(jù) 
  13. s:套接字 
  14. buf:發(fā)送數(shù)據(jù)的緩沖區(qū) 
  15. len:發(fā)送數(shù)據(jù)緩沖區(qū)的大小 
  16. flags:該參數(shù)影響sendto()函數(shù)的行為。參數(shù)可以為0(表示無(wú)特殊行為);MSG_DONTROUTE(標(biāo)志要求傳輸層不要將數(shù)據(jù)路由出去);MSG_OOB(標(biāo)志預(yù)示該數(shù)據(jù)應(yīng)該被帶外發(fā)送); 
  17. to:接收數(shù)據(jù)的地址 
  18. tolen:地址長(zhǎng)度 
  19. 返回值:成功則返回發(fā)送數(shù)據(jù)的字節(jié)數(shù),否則返回SOCKET_ERROR 
  20. */  
  21.   
  22.   
  23. /* 
  24. 1.getsockopt()函數(shù) 
  25. int getsockopt(SOCKET s,int level,int optname,char FAR* optval,int FAR* optlen);用于獲取套接字選項(xiàng)信息 
  26. s:套接字 
  27. level:選項(xiàng)級(jí)別,有SOL_SOCKET,IPPROTO_TCP兩個(gè)級(jí)別 
  28. optname:套接字選項(xiàng)名稱 
  29. optval:接收數(shù)據(jù)緩沖區(qū),該參數(shù)返回套接字選項(xiàng)名稱對(duì)應(yīng)的值 
  30. optlen:緩沖區(qū)大小 
  31. 返回值:成功返回0,否則返回SOCKET_ERROR 
  32.  
  33. 2.setsockopt()函數(shù) 
  34. int setsockopt(SOCKET s,int level,int optname,const char FAR* optval,int optlen);設(shè)置套接字選項(xiàng) 
  35. s:套接字 
  36. level:選項(xiàng)級(jí)別:有SOL_SOCKET和IPPROTO_TCP兩個(gè)級(jí)別 
  37. optname:套接字選項(xiàng)名稱 
  38. optval:該參數(shù)用于設(shè)置套接字選項(xiàng)的值 
  39. optlen:緩沖區(qū)大小 
  40. 返回值:成功返回0,否則返回SOCKET_ERROR 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多