学习内容,参见《Windows网络编程》第7章 Winsock基础
与TCP流式协议不同,UDP为数据报协议。
服务端接受数据,客户端发送数据。
UDP服务端流程
UDP客户端流程
UDP客户端有两种方式,一种为无连接,一种为创建虚拟连接。
方式一 无连接
方式二 建立虚拟连接
使用windows的Winsock 2编程,需要进行工程配置。
备注:所有关系到收发数据的缓冲都属于简单的char类型,这些函数没有Unicode版本。当字符集为Unicode时,需要进行字符串转换。
服务端源码,UDPServer.cpp。
// UDPServer.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <WinSock2.h> #include <stdio.h> #include <stdlib.h> #define DEFAULT_PORT 5150 #define DEFAULT_COUNT 5 #define DEFAULT_BUFFER_LENGTH 4096 int iPort = DEFAULT_PORT; DWORD dwCount = DEFAULT_COUNT; DWORD dwLength = DEFAULT_BUFFER_LENGTH; BOOL bInterface = FALSE; char szIterface[32]; //Print usage information and exit void usage() { printf("usage:sender[-p:int][-i:IP][-n:x][-b:x]\n\n"); printf(" -p:int Local port\n"); printf(" -i:IP Local IP address to listen on\n"); printf(" -n:x Number of times to send message\n"); printf(" -b:x Size of buffer to send \n\n"); ExitProcess(1); } //ValidateArgs void ValidateArgs(int argc, _TCHAR** argv) { for (int i = 1; i < argc; i++) { if ((argv[i][0] == _T('-') || (argv[i][0] == _T('/')))) { switch (tolower(argv[i][1])) { case _T('p'): if (_tcslen(argv[i]) > 3) { iPort = _ttoi(&argv[i][3]); } break; case _T('n'): //Number of times to receive message if (_tcslen(argv[i]) > 3) { dwCount = _ttol(&argv[i][3]); } break; case _T('b'): //Buffer size if (_tcslen(argv[i]) > 3) { dwLength = _ttol(&argv[i][3]); } break; case _T('i'): //Interface to receive datagrams on if (_tcslen(argv[i]) > 3) { bInterface = TRUE; _tcscpy_s(szIterface, &argv[i][3]); } break; default: usage(); break; } } } } int _tmain(int argc, _TCHAR* argv[]) { //Parse arguments and load winsock ValidateArgs(argc, argv); WSADATA wsd; if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { printf("WSAStartup failed!\n"); return 1; } //Create the socket, and bind it to a local interface and port SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (s == INVALID_SOCKET) { printf("socket() failed:%d\n", WSAGetLastError()); return 1; } SOCKADDR_IN local; local.sin_family = AF_INET; local.sin_port = htons((short)iPort); if (bInterface) { local.sin_addr.s_addr = inet_addr(szIterface); } else { local.sin_addr.s_addr = htonl(INADDR_ANY); } if (bind(s, (SOCKADDR*)&local, sizeof(local)) == SOCKET_ERROR) { printf("bind() failed:%d\n", WSAGetLastError()); return 1; } //Allocate the receive buffer char* recvbuf = (char*)GlobalAlloc(GMEM_FIXED, dwLength); if (!recvbuf) { printf("GlobalAlloc() failed:%d\n", GetLastError()); return 1; } //Read the datagrams SOCKADDR_IN sender; for (int i = 0; i < (int)dwCount; i++) { int nSenderSize = sizeof(sender); int ret = recvfrom(s, recvbuf, dwLength, 0, (SOCKADDR*)&sender, &nSenderSize); if (ret == SOCKET_ERROR) { printf("recvfrom() failed:%d\n", WSAGetLastError()); break; } else if (ret == 0) { break; } else { recvbuf[ret] = _T('\0'); printf("[%s] sent me:'%s'\n", inet_ntoa(sender.sin_addr), recvbuf); } } closesocket(s); GlobalFree(recvbuf); WSACleanup(); return 0; }
// UDPClient.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <WinSock2.h> #include <stdio.h> #include <stdlib.h> #define DEFAULT_PORT 5150 #define DEFAULT_COUNT 25 #define DEFAULT_CHAR 'a' #define DEFAULT_BUFFER_LENGTH 32 BOOL bConnect = FALSE; int iPort = DEFAULT_PORT; char cChar = DEFAULT_CHAR; DWORD dwCount = DEFAULT_COUNT; DWORD dwLength = DEFAULT_BUFFER_LENGTH; char szRecipient[128]; //Print usage information and exit void usage() { printf("usage:sender[-p:int][-r:IP][-c][-n:x][-b:x][-d:c]\n\n"); printf(" -p:int Remote port\n"); printf(" -r:IP Recipient's IP address or host name\n"); printf(" -c Connect to remote IP first\n"); printf(" -n:x Number of times to send message\n"); printf(" -b:x Size of buffer to send\n"); printf(" -d:c Character to fill buffer with\n\n"); ExitProcess(1); } //Parse the command line arguments, and set some global flags to //indicate what actions to perform void ValidateArgs(int argc, _TCHAR** argv) { for (int i = 1; i < argc; i++) { if ((argv[i][0] == _T('-') || (argv[i][0] == _T('/')))) { switch (tolower(argv[i][1])) { case _T('p'): //Remote port if (_tcslen(argv[i]) > 3) { iPort = _ttoi(&argv[i][3]); } break; case _T('r'): //Recipient's IP addr if (_tcslen(argv[i]) > 3) { _tcscpy_s(szRecipient, &argv[i][3]); } break; case _T('c'): //Connect to recipient's IP addr bConnect = TRUE; break; case _T('n'): if (_tcslen(argv[i]) > 3) { dwCount = _ttol(&argv[i][3]); } break; case _T('b'): if (_tcslen(argv[i]) > 3) { dwLength = _ttol(&argv[i][3]); } break; case _T('d'): cChar = argv[i][3]; break; default: usage(); break; } } } } int _tmain(int argc, _TCHAR* argv[]) { ValidateArgs(argc, argv); WSADATA wsd; if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { printf("WSAStartup failed!\n"); return 1; } //Crate the socket SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (s == INVALID_SOCKET) { printf("socket() failed:%d\n", WSAGetLastError()); return 1; } //Resolve the recipient's IP address or host name SOCKADDR_IN recipient; recipient.sin_family = AF_INET; recipient.sin_port = htons((short)iPort); int nServerLen = (int)_tcslen(szRecipient); if (0 == nServerLen) { struct hostent* host = gethostbyname(szRecipient); if (host == NULL) { printf("gethostbyname() failed:%d\n", WSAGetLastError()); WSACleanup(); return 1; } CopyMemory(&recipient.sin_addr, host->h_addr_list[0], host->h_length); } else { recipient.sin_addr.s_addr = inet_addr(szRecipient); } //Allocate the send buffer char* sendbuf = (char*)GlobalAlloc(GMEM_FIXED, dwLength); if (!sendbuf) { printf("GlobalAlloc() failed:%d\n", GetLastError()); return 1; } memset(sendbuf, cChar, dwLength); if (bConnect) { //If the connect option is set, "connect" to the recipient //and send the data with the send() fuction if (connect(s, (SOCKADDR*)&recipient, sizeof(recipient)) == SOCKET_ERROR) { printf("connect() failed:%d\n", WSAGetLastError()); GlobalFree(sendbuf); WSACleanup(); return 1; } for (int i = 0; i < (int)dwCount; i++) { int ret = send(s, sendbuf, dwLength, 0); if (ret == SOCKET_ERROR) { printf("send() failed:%d\n", WSAGetLastError()); break; } else if (ret == 0) { break; } } } else { //Otherwise, use the sendto() function for (int i = 0; i < (int)dwCount; i++) { int ret = sendto(s, sendbuf, dwLength, 0, (SOCKADDR*)&recipient, sizeof(recipient)); if (ret == SOCKET_ERROR) { printf("send() failed:%d\n", WSAGetLastError()); break; } else if (ret == 0) { break; } } } closesocket(s); GlobalFree(sendbuf); WSACleanup(); return 0; }