与TCP协议下编写服务端程序代码类似,但因为是无连接的形式,所以不需要监听。
这次,我用了一点不同的想法:我建立一个服务端,用了两个端口和两个套接字,把服务端作为一个数据转发的中转站,使得客户机之间进行UDP协议下的通信。
服务端代码:
/** * UDP/IP 服务器端 Server.c */ #include <winsock2.h> #include <stdio.h> #include <string.h> #include <time.h> #define true 1 #define false 0 #define BUFFSIZE 1024 int main(int argc, char**argv) { int Ret; WSADATA wsaData; SOCKET Socket_1; SOCKET Socket_2; SOCKADDR_IN ClientAddr_1; int ClientAddr_1_Len = sizeof(ClientAddr_1); SOCKADDR_IN ClientAddr_2; int ClientAddr_2_Len = sizeof(ClientAddr_2); unsigned short Port_1 = 5150; unsigned short Port_2 = 8888; char sendData[BUFFSIZE]; char recvData[BUFFSIZE]; if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0) { printf("WSASTARTUP_ERROR: %d\n", Ret); exit(1); } if((Socket_1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { printf("Socket_1_ERROR\n"); exit(1); } //将端口变量从主机字节顺序转换位网络字节顺序 ClientAddr_1.sin_family = AF_INET; ClientAddr_1.sin_port = htons(Port_1); ClientAddr_1.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //使用bind将这个地址信息和套接字绑定起来 if(bind(Socket_1, (SOCKADDR *)&ClientAddr_1, ClientAddr_1_Len) == SOCKET_ERROR) { printf("BIND_SOCKET_1_ERROR: %d\n", SOCKET_ERROR); exit(1); } if((Socket_2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { printf("Socket_2_ERROR\n"); exit(1); } //将端口变量从主机字节顺序转换位网络字节顺序 ClientAddr_2.sin_family = AF_INET; ClientAddr_2.sin_port = htons(Port_2); ClientAddr_2.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //使用bind将这个地址信息和套接字绑定起来 if(bind(Socket_2, (SOCKADDR *)&ClientAddr_2, ClientAddr_2_Len) == SOCKET_ERROR) { printf("BIND_SOCKET_2_ERROR: %d\n", SOCKET_ERROR); exit(1); } printf("建立连接成功!"); //服务器作为中转站 //为两个IP之间互相转发消息 while(true) { //接收IP:192.168.1.2发送的数据 recvfrom(Socket_1, recvData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr_1, &ClientAddr_1_Len); strcpy(sendData, recvData); //转发数据给IP:192.168.1.6 if((Ret = sendto(Socket_2, sendData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr_2, ClientAddr_2_Len)) < 0) printf("发送失败!\n"); //接收IP:192.168.1.6发送的数据 recvfrom(Socket_2, recvData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr_2, &ClientAddr_2_Len); strcpy(sendData, recvData); //转发数据给IP:192.168.1.2 if((Ret = sendto(Socket_1, sendData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr_1, ClientAddr_1_Len)) < 0) printf("发送失败!\n"); } closesocket(Socket_1); closesocket(Socket_2); //应用程序完成对接的处理后,调用WSACleanup if(WSACleanup() == SOCKET_ERROR) { printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError()); exit(1); } system("pause"); return 0; }
但会有个小问题,首先发送数据的客户端的数据无法接收,而且要运行成功必须先发送一个信息,再打开第二个客户端(步骤貌似是这样,前段时间写的了,忘记了...= =)
客户端1代码:
/** * UDP/IP 客户端 Client.c */ #include <winsock2.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define true 1 #define false 0 #define BUFFSIZE 1024 int main(int argc, char**argv) { int Ret; WSADATA wsaData; SOCKET SendSocket; SOCKADDR_IN ClientAddr; int ClientAddrLen = sizeof(ClientAddr); unsigned short Port = 5150; char sendData[BUFFSIZE]; char recvData[BUFFSIZE]; time_t rawtime; if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0) { printf("WSASTARTUP_ERROR: %d\n", Ret); exit(1); } if((SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { printf("SendSOCKET_ERROR\n"); exit(1); } ClientAddr.sin_family = AF_INET; ClientAddr.sin_port = htons(Port); ClientAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.2");//本机IPv4地址 printf("连接到IP:%s 端口:%d\n", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port)); puts("-----开始聊天!-----"); //这样的循环聊天算法硬生生的把UDP协议弄得和前面TCP协议的聊天程序一样了。。。 //感觉并不太能表现UDP和TCP的区别。。。但我暂时没有好办法 while(true) { //发送数据 printf("\nC.C.:"); scanf("%s", sendData); strcat(sendData, "\t____"); time(&rawtime); strcat(sendData, ctime(&rawtime)); if((Ret = sendto(SendSocket, sendData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr, ClientAddrLen)) < 0) printf("发送失败!\n"); //接收数据 if((Ret = recvfrom(SendSocket, recvData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr, &ClientAddrLen)) >= 0) printf("鲁鲁:%s\n", recvData); else printf("接收失败!\n"); } closesocket(SendSocket); if(WSACleanup() == SOCKET_ERROR) { printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError()); exit(1); } system("pause"); return 0; }
按照思路即可编写客户端2的代码,代码也基本一样,就是端口号不能一样,需要对应服务端给定的另外一个端口号:
/** * UDP/IP 客户端 Client.c */ #include <winsock2.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define true 1 #define false 0 #define BUFFSIZE 1024 int main(int argc, char**argv) { int Ret; WSADATA wsaData; SOCKET SendSocket; SOCKADDR_IN ClientAddr; int ClientAddrLen = sizeof(ClientAddr); unsigned short Port = 8888; char sendData[BUFFSIZE]; char recvData[BUFFSIZE]; time_t rawtime; if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0) { printf("WSASTARTUP_ERROR: %d\n", Ret); exit(1); } if((SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { printf("SendSOCKET_ERROR\n"); exit(1); } ClientAddr.sin_family = AF_INET; ClientAddr.sin_port = htons(Port); ClientAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.2");/** * 服务端程序的计算机的IPv4地址 * 显然这整个聊天程序至少需要两台电脑,一台电脑可以为服务端和客户端,另外再一台电脑为客户端。或者有三台电脑就更不容易糊涂了,一台作为服务端,另外两台都是客户端。*/ printf("连接到IP:%s 端口:%d\n", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port)); puts("-----开始聊天!-----"); while(true) { //接收数据 if((Ret = recvfrom(SendSocket, recvData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr, &ClientAddrLen)) >= 0) printf("C.C.:%s\n", recvData); else printf("接收失败!\n"); //发送数据 printf("\n鲁鲁:"); scanf("%s", sendData); strcat(sendData, "\t____"); time(&rawtime); strcat(sendData, ctime(&rawtime)); if((Ret = sendto(SendSocket, sendData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr, ClientAddrLen)) < 0) printf("发送失败!\n"); } closesocket(SendSocket); if(WSACleanup() == SOCKET_ERROR) { printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError()); exit(1); } system("pause"); return 0; }