[C语言]一个很实用的服务端和客户端进行UDP通信的实例
前段時間發了個TCP通信的例子,現在再來一個UDP通信的例子。這些可以作為樣本程序,用到開發中。“裸寫”socket老是記不住步驟,經常被鄙視……
下面的例子很簡單,寫一個UDP的server用于收包,寫一個UDP的client用于發包并接收來自server的回復。其中UDP的client寫了兩個,一個是不需要connect的,另一個是帶上connect的,兩個client實現的功能是一樣的。從效率上,帶上connect的UDP肯定效率稍微高一些。不過UDP的connect和TCP里面非常不一樣。在UDP里面connect的時候并沒有三次握手的過程,但是它指定了與自己通信的對方的具體地址,內核中會將次地址記錄下來,如果你的UDP就是在確定了兩臺機器之間傳送信息,建議選取帶有connect的套接字。connect之后與對方通信直接write或者read函數就可以,不用再指定對方ip和port,并且connect之后的套接字可以自動過濾掉不是來自指定通信方的信息。UDP可以調用多次connect函數,但是TCP套接字只能調用一次,再次調用會出現錯誤。
1. 首先是服務端的程序:
UDPserver.cpp
1 #include <stdio.h> 2 #include <string.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/socket.h> 6 #include <stdlib.h> 7 #include <netinet/in.h> 8 #include <arpa/inet.h> 9 10 #define PORT 1234 11 #define MAXDATASIZE 100 12 13 int main(void) 14 { 15 int sockfd; 16 struct sockaddr_in server; 17 struct sockaddr_in client; 18 socklen_t len; 19 int num; 20 char buf[MAXDATASIZE]; 21 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 22 { 23 perror("Creating socket failed.\n"); 24 exit(1); 25 } 26 bzero(&server, sizeof(server)); 27 server.sin_family = AF_INET; 28 server.sin_port = htons(PORT); 29 server.sin_addr.s_addr = htonl(INADDR_ANY); 30 if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1) 31 { 32 perror("Bind() error.\n"); 33 exit(1); 34 } 35 36 len = sizeof(client); 37 while(1) 38 { 39 num = recvfrom(sockfd, buf, MAXDATASIZE, 0, (struct sockaddr *)&client, &len); 40 if(num < 0) 41 { 42 perror("recvfrom() error.\n"); 43 exit(1); 44 } 45 buf[num] = '\0'; 46 printf("You got a message <%s> from client. \nIt's ip is %s, port is %d. \n", buf, inet_ntoa(client.sin_addr),htons(client.sin_port)); 47 sendto(sockfd, "Welcome\n", 8, 0, (struct sockaddr *)&client, len); 48 if ( !strcmp(buf, "bye") ){ 49 break; 50 } 51 } 52 close(sockfd); 53 }?
2. 然后,我們給出帶有connect的客戶端程序:
UDPclientWithConnect.cpp
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <netinet/in.h> 8 #include <netdb.h> 9 #include <arpa/inet.h> 10 11 #define PORT 1234 12 13 #define MAXDATASIZE 100 14 15 int main(int argc, char *argv[]) 16 { 17 int sockfd, num; 18 char buf[MAXDATASIZE]; 19 struct hostent *he; 20 struct sockaddr_in server, peer; 21 if(argc != 3) 22 { 23 printf("Usage: %s <IP address> <message>\n", argv[0]); 24 exit(1); 25 } 26 27 if((sockfd=socket(AF_INET, SOCK_DGRAM, 0)) == -1) 28 { 29 printf("socket() error\n"); 30 exit(1); 31 } 32 bzero(&server, sizeof(server)); 33 server.sin_family = AF_INET; 34 server.sin_port = htons(PORT); 35 36 server.sin_addr.s_addr = inet_addr(argv[1]); 37 //server.sin_addr.s_addr = inet_addr(argv[1]); 38 if(connect(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1) 39 { 40 printf("connect() error.\n"); 41 exit(1); 42 } 43 44 send(sockfd, argv[2], strlen(argv[2]), 0); 45 46 while(1) 47 { 48 if((num = recv(sockfd, buf, MAXDATASIZE, 0)) == -1) 49 { 50 printf("recv() error.\n"); 51 exit(1); 52 } 53 54 buf[num] = '\0'; 55 printf("Server Message: %s.\n", buf); 56 break; 57 } 58 close(sockfd); 59 }?
3. 最后,再給一個不帶connect的客戶端程序。
UDPclientNoConnect.cpp
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h>#define PORT 1234#define MAXDATASIZE 100int main(int argc, char *argv[]) {int sockfd, num;char buf[MAXDATASIZE];struct hostent *he;struct sockaddr_in server, peer;if(argc != 3){printf("Usage: %s <IP address> <message>\n", argv[0]);exit(1);}if((he = gethostbyname(argv[1]))==NULL){printf("gethostbyname() error\n");exit(1);}if((sockfd=socket(AF_INET, SOCK_DGRAM, 0)) == -1){printf("socket() error\n");exit(1);}bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr = *( (struct in_addr *)he->h_addr);sendto(sockfd, argv[2], strlen(argv[2]), 0, (struct sockaddr *)&server, sizeof(server));socklen_t len;len = sizeof(server);while(1){if((num = recvfrom(sockfd, buf, MAXDATASIZE, 0, (struct sockaddr *)&peer, &len)) == -1){printf("recvfrom() error\n");exit(1);}if(len != sizeof(server) || memcmp((const void *)&server, (const void *)&peer, len) != 0 ){printf("Receive message from other server.\n");continue;}buf[num] = '\0';printf("Server Message: %s.\n", buf);break;}close(sockfd); }?
執行一下命令進行編譯:
$ g++ -o UDPserver UDPserver.cpp
$ g++ -o UDPclient2 UDPclientWithConnect.cpp
$ g++ -o UDPclient1 UDPclientNoConnect.cpp
完了以后就看到三個可執行文件了。
打開一個命令行,執行./UDPserver啟動服務端程序,再打開另外一個命令行,執行./UDPclient1 127.0.0.1 "nihaonihao"或者./UDPclient2 127.0.0.1 "testtest"即可查看到以下效果:
[horstxu@vps ~/Cprog/udpCSmodel]$ ./UDPserver You got a message <nihaonihao> from client. It's ip is 127.0.0.1, port is 25595. You got a message <testtest> from client. It's ip is 127.0.0.1, port is 27396.?
[horstxu@vps ~/Cprog/udpCSmodel]$ ./UDPclient1 127.0.0.1 "nihaonihao" Server Message: Welcome . [horstxu@vps ~/Cprog/udpCSmodel]$ ./UDPclient2 127.0.0.1 "testtest" Server Message: Welcome . [horstxu@vps ~/Cprog/udpCSmodel]$?
最后再來解釋一個帶有connect的UDP的好處。由于UDP是不可靠傳輸,如果我發了數據出去,對方其實服務器是關閉的,這時會有什么結果呢?對于剛才的UDPclient1,也就是不帶connect的,客戶端程序會卡在recvfrom這里,因為對方是關閉的,它永遠也收不到來自對方的回包。但是對于UDPclient2,也就是帶有connect,我們其實可以收到一個錯誤,并設置errno(errno:111,connection refused)。這樣看上去就比卡死在那里友好多了。對于這個問題的具體分析可以參考這篇文章:
UDP怎么會返回Connection refused錯誤
[horstxu@vps ~/Cprog/udpCSmodel]$ ./UDPclient2 127.0.0.1 "testtest" recv() error. [horstxu@vps ~/Cprog/udpCSmodel]$ ./UDPclient1 127.0.0.1 "testtest" #注釋:程序在這里卡死?
轉載于:https://www.cnblogs.com/xuning/p/4614458.html
總結
以上是生活随笔為你收集整理的[C语言]一个很实用的服务端和客户端进行UDP通信的实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是核显(核显是什么意思)
- 下一篇: 情侣存钱恋爱基金怎么弄 情侣要存钱怎么弄