下面是UDPServer項目裏面的udpServer.cpp的代碼socket
//做者:劉日輝 //時間:2019-5-9 //用途:UDP教學 #include "stdafx.h" #include <stdio.h> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") int main(int argc, char* argv[]) { //初始化WSA WSADATA wsaData; //建立兩個字節的word格式 WORD sockVersion = MAKEWORD(2,2); //WSAStartup用來初始化winsock的DLL庫,執行成功後返回0,失敗後則返回socket_error if(WSAStartup(sockVersion, &wsaData) != 0) { return 0; } //建立套接字 //socket(int af,int type,int protocol) //af 是通訊協議的類型,type建立套接字的類型,protocol取決於第二個參數用於指定套接字的協議 //函數成功後返回套接字描述符,失敗返回socket_error SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //INVALID英文含義是無效的 if(serSocket == INVALID_SOCKET) { printf("socket error !"); return 0; } //綁定IP和端口 //sockaddr_in,該結構體把port和addr 分開儲存在兩個變量中,以下: /* struct sockaddr_in { sa_family_t sin_family;//地址族(Address Family) unit16_t sin_port;//16位TCP/UDP端口號 struct in_addr sin_addr;//32位IP地址 char sin_zero[8];//不使用 } struct in_addr { In_addr_t s_addr;//32位IPV4地址 } */ sockaddr_in serAddr; serAddr.sin_family = AF_INET; serAddr.sin_port = htons(8888); serAddr.sin_addr.S_un.S_addr = INADDR_ANY; /* bind(sockt s,const struct socketaddr * name,int namelen),執行成功返回0, 不然返回socket_error name 指定告終構體的套接字地址,namelen是地址結構的長度 */ if(bind(serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR) { printf("bind error !"); closesocket(serSocket); return 0; } //新建一個套接字結構體數據 sockaddr_in remoteAddr; //獲取結構體的存儲容量 int nAddrLen = sizeof(remoteAddr); //循環接收數據 while (true) { /*接收數據 recvfrom(socket s,char *buf,int len,int flags,const char * from ,int fromlen) 用於接受數據報套接字的數據, s是接收端套接字, buf 指定接收端等待接受數據的緩衝區, len 指定要接受的數據的字節數, flags指定要附加的標誌位,一般flags設置爲0, from指定存放發送端等待發送數據的緩衝區, fromlen指定要發送數據的字節數。 函數執行成功後返回接收數據的字節數,失敗後返回socket_error */ char recvData[255]; int ret = recvfrom(serSocket, recvData, 255, 0, (sockaddr *)&remoteAddr, &nAddrLen); if (ret > 0) { //0x00是16進制的寫法,含義是0 //ret是接收數據的長度,咱們初始定義的revData長度是255, //下面一句話的意思是讓超過ret後面的內容爲空 recvData[ret] = 0x00; printf("接受到一個鏈接:%s \r\n", inet_ntoa(remoteAddr.sin_addr)); printf(recvData); } //發送數據 char * sendData = "一個來自服務端的UDP數據包\n"; /* sendto(socket s,const char *buf,int flags,const char * to,int tolen) 用於發送數據,s是發送端套接字描述符, buf指定發送端等待發送數據的緩衝區, len指定要發送數據的字節數, flags指定須要附加的標誌位, 一般flags設置爲0, to指定存放接收端等待接收數據的緩衝區, tolen指定要接收數據的字節數。 函數執行成功後返回發送數據的字節數,失敗後返回socket_error */ sendto(serSocket, sendData, strlen(sendData), 0, (sockaddr *)&remoteAddr, nAddrLen); } //關閉監聽的套接字,並釋放套接字所佔用的資源 closesocket(serSocket); /* 卸載winsocket的dll,操做系統會解除應用程序與socket dll 庫的綁定, 並釋放socket dll 庫所佔用的系統資源 */ WSACleanup(); return 0; }
下面是UDpClient裏面的udpClent.cpp代碼及解析:函數
//做者:劉日輝 //時間:2019-5-9 //用途:UDP教學 #include "stdafx.h" #include <stdio.h> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") int main(int argc, char* argv[]) { //初始化WSA //建立兩個字節的word格式 WORD socketVersion = MAKEWORD(2,2); //建立一個結構,用來存儲被WSAStartup函數調用後返回的Windows Sockets數據 WSADATA wsaData; //WSAStartup用來初始化winsock的DLL庫,執行成功後返回0,失敗後則返回socket_error if(WSAStartup(socketVersion, &wsaData) != 0) { return 0; } //socket(int af,int type,int protocol) //af 是通訊協議的類型,type建立套接字的類型,protocol取決於第二個參數用於指定套接字的協議 //函數成功後返回套接字描述符,失敗返回socket_error SOCKET sclient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //sockaddr_in,該結構體把port和addr 分開儲存在兩個變量中,以下: /* struct sockaddr_in { sa_family_t sin_family;//地址族(Address Family) unit16_t sin_port;//16位TCP/UDP端口號 struct in_addr sin_addr;//32位IP地址 char sin_zero[8];//不使用 } struct in_addr { In_addr_t s_addr;//32位IPV4地址 } */ sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(8888); sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); int len = sizeof(sin); char * sendData = "來自客戶端的數據包.\n"; /* sendto(socket s,const char *buf,int flags,const char * to,int tolen) 用於發送數據,s是發送端套接字描述符, buf指定發送端等待發送數據的緩衝區, len指定要發送數據的字節數, flags指定須要附加的標誌位, 一般flags設置爲0, to指定存放接收端等待接收數據的緩衝區, tolen指定要接收數據的字節數。 函數執行成功後返回發送數據的字節數,失敗後返回socket_error */ sendto(sclient, sendData, strlen(sendData), 0, (sockaddr *)&sin, len); char recvData[255]; /*接收數據 recvfrom(socket s,char *buf,int len,int flags,const char * from ,int fromlen) 用於接受數據報套接字的數據, s是接收端套接字, buf 指定接收端等待接受數據的緩衝區, len 指定要接受的數據的字節數, flags指定要附加的標誌位,一般flags設置爲0, from指定存放發送端等待發送數據的緩衝區, fromlen指定要發送數據的字節數。 函數執行成功後返回接收數據的字節數,失敗後返回socket_error */ int ret = recvfrom(sclient, recvData, 255, 0, (sockaddr *)&sin, &len); if(ret > 0) { //0x00是16進制的寫法,含義是0 //ret是接收數據的長度,咱們初始定義的revData長度是255, //下面一句話的意思是讓超過ret後面的內容爲空 recvData[ret] = 0x00; printf(recvData); } //關閉監聽的套接字,並釋放套接字所佔用的資源 closesocket(sclient); /* 卸載winsocket的dll,操做系統會解除應用程序與socket dll 庫的綁定, 並釋放socket dll 庫所佔用的系統資源 */ WSACleanup(); return 0; }