学习内容,参见《Windows网络编程》第7章 Winsock基础
与TCP流式协议不同,UDP为数据报协议。
服务端接受数据,客户端发送数据。
UDP服务端流程
- Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
- bind绑定到IP地址和端口。
- recvfrom/WSARecvFrom接受数据。
UDP客户端流程
UDP客户端有两种方式,一种为无连接,一种为创建虚拟连接。
方式一 无连接
- Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
- 设置服务器地址和端口。
- sento/WSASendTo发送数据。
方式二 建立虚拟连接
- Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
- 设置服务器地址和端口。
- connect连接服务端。
- 调用send发送数据。
使用windows的Winsock 2编程,需要进行工程配置。
- 工程右键Properties->ConfigurationProperties->Linker->Input->Additional Dependencies中添加ws2_32.lib。
- Demo代码采用Multi-Byte方式,设置Properties->ConfigurationProperties->General->Character Set为Use Multi-Byte Character Set。
备注:所有关系到收发数据的缓冲都属于简单的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。
- // 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;
- }
http://blog.csdn.net/segen_jaa/article/details/7565689