UDP特点:基于报文、不保证按序发送、一对一,一对多,多对一和多对多的交互通信、不可靠性(容易出现丢包现象)。
服务端: 创建socket-->bind-->循环接收/发送数据-->关闭socket
客户端:创建socket-->bind(可选)-->循环发送/接收数据-->关闭socket
流程图:
UDP编程的服务端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、bind绑定IP地址、端口等信息到socket上;
4、循环接收数据,用函数recvfrom();
5、关闭网络连接;
UDP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、bind绑定IP地址、端口等信息到socket上;* 可选
4、设置对方的IP地址和端口等属性;
5、发送数据,用函数sendto();
6、关闭网络连接;
UDP.h
#pragma once
#include
// UDP服务端
class CUDPServer
{
public:
CUDPServer()
{
m_terminal = false;
}
~CUDPServer() {}
// 服务端
long UDPServer();
// 接收客户端数据
long RecvClientData();
private:
char recvClientBuf[100];
SOCKET sockSrv;
SOCKADDR_IN addrClient; //用来接收客户端的地址信息
bool m_terminal;
};
// UDP客户端
class CUDPClient
{
public:
CUDPClient() {}
~CUDPClient() {}
// 客户端
long UDPClient();
// 接收服务端数据
long RecvServerData();
private:
char recvServerBuf[100];
SOCKET sockClient;
SOCKADDR_IN addrSrv;
};
UDP.cpp
#include "stdafx.h"
#include "UDP.h"
#include
#include
#pragma comment( lib, "ws2_32.lib" )
// 服务端
long CUDPServer::UDPServer()
{
//初始化winsocket
WORD wVersionRequested;
WSADATA wsaData;
int nPort = 8888; //端口号
//第一个参数为低位字节;第二个参数为高位字节
wVersionRequested = MAKEWORD(1, 1); //声明调用不同的Winsock版本。例如MAKEWORD(2,2)就是调用2.2版,MAKEWORD(1,1)就是调用1.1版
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
return -1;
}
//对winsock DLL初始化
if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
WSACleanup();
return -1;
}
//1、创建一个socket,用函数socket()
sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
if (sockSrv < 0)
{
printf("udp server creat socket error\n");
return -1;
}
printf("udp server creat socket success\n");
//2、设置socket属性,用函数setsockopt(); 可选
SOCKADDR_IN local; //定义sockSrv发送和接收数据包的地址
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //htonl用来将主机字节顺序转换为网络字节顺序(to network long) INADDR_ANY就是指定地址为0.0.0.0的地址
local.sin_family = AF_INET; //设置为IP通信
local.sin_port = htons(nPort); //服务器端口号
//3、绑定IP地址、端口等信息到socket上,用函数bind()
int len = sizeof(SOCKADDR);
int nRes = bind(sockSrv, (SOCKADDR*)&local, len);
if (nRes < 0)
{
printf("udp server bind IP error\n");
return -1;
}
printf("udp server bind success\n");
printf("udp server accept client ip is:[%s]\n", inet_ntoa(local.sin_addr));
printf("udp server to client sent data, please input:\n");
// 4、循环等待接收数据,用函数recvfrom()
std::thread th1(std::bind(&CUDPServer::RecvClientData, this));
th1.detach();
char buffs[100];
while (!m_terminal)
{
//sendto发送数据
memset(buffs, 100, 0);
std::cin.getline(buffs, 100);
if (0 == std::strcmp(buffs, "q")) //服务端退出
{
printf("udp server quit...\n");
sendto(sockSrv, buffs, strlen(buffs) + 1, 0, (SOCKADDR*)&addrClient, len);
m_terminal = true;
break;
}
sendto(sockSrv, buffs, strlen(buffs) + 1, 0, (SOCKADDR*)&addrClient, len);
}
// 5、关闭网络连接
closesocket(sockSrv);
printf("udp server close socket...\n");
WSACleanup();
return 0;
}
long CUDPServer::RecvClientData()
{
int len = sizeof(SOCKADDR);
while (!m_terminal) {
memset(recvClientBuf, 100, 0);
int nLen = recvfrom(sockSrv, recvClientBuf, 100, 0, (SOCKADDR*)&addrClient, &len);
if (nLen <= 0) //检测客户端退出
{
printf("client connect close, please check[%d]....\n", nLen);
break;
}
if (0 == std::strcmp(recvClientBuf, "q")) //判断客户端退出
{
printf("udp client quit...\n");
continue;
}
printf("%s\n", recvClientBuf);
}
return 0;
}
// 客户端
long CUDPClient::UDPClient()
{
//初始化winsocket
WORD wVersionRequested;
WSADATA wsaData;
int nPort = 8888; //端口号
//第一个参数为低位字节;第二个参数为高位字节
wVersionRequested = MAKEWORD(1, 1); //声明调用不同的Winsock版本。例如MAKEWORD(2,2)就是调用2.2版,MAKEWORD(1,1)就是调用1.1版
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
return -1;
}
//对winsock DLL初始化
if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
WSACleanup();
return -1;
}
//1、创建一个socket,用函数socket()
sockClient = socket(AF_INET, SOCK_DGRAM, 0);
if (sockClient < 0)
{
printf("udp client creat socket error\n");
return -1;
}
//2、设置socket属性,用函数setsockopt(); 可选
//SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(nPort);
printf("udp cilent accept server ip is:[%s]\n", inet_ntoa(addrSrv.sin_addr));
printf("udp cilent to server sent data, please input:\n");
int len = sizeof(SOCKADDR);
//发送信息与服务器建立连接(必须加)
sendto(sockClient, "begin connect server", strlen("begin connect server"), 0, (SOCKADDR*)&addrSrv, len);
//接收数据,线程接收数据
std::thread th1(std::bind(&CUDPClient::RecvServerData, this));
th1.detach();
//char recvBuf[100];
while (true)
{
//3、发送数据,用函数sendto()
char buffs[100];
std::cin.getline(buffs, 100);
if (0 == std::strcmp(buffs, "q")) //客户端主动退出
{
printf("udp client quit\n");
sendto(sockClient, buffs, strlen(buffs) + 1, 0, (SOCKADDR*)&addrSrv, len);
break;
}
int nSent = sendto(sockClient, buffs, strlen(buffs) + 1, 0, (SOCKADDR*)&addrSrv, len);
}
//4、关闭网络连接;
closesocket(sockClient);
WSACleanup();
return 0;
}
long CUDPClient::RecvServerData()
{
int len = sizeof(SOCKADDR);
while (true) {
memset(recvServerBuf, 100, 0);
int nRes = recvfrom(sockClient, recvServerBuf, 100, 0, (SOCKADDR*)&addrSrv, &len);
if (nRes <= 0) //检测客户端退出
{
printf("udp client connect close, please check....\n");
break;
}
if (0 == std::strcmp(recvServerBuf, "q")) //判断服务端退出
{
printf("udp server quit...\n");
continue;
}
printf("%s\n", recvServerBuf);
}
return 0;
}
main 调用:
int main()
{
//测试UDP客户端
std::shared_ptr pUDPClient = std::make_shared();
pUDPClient->UDPClient();
//测试UDP服务端
//std::shared_ptr pUDPServer = std::make_shared();
//pUDPServer->UDPServer();
}
运行结果: