C++ UDP通信

流程图
在这里插入图片描述

头文件和库

#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

初始化套接字库

初始化函数:

int WSAAPI WSAStartup
(
WORD wVersionRequested,
LPWSADATA lpWSAData
);
返回值:如果申请成功,返回值为 0,失败直接返回失败的代码,无法调用WSAGetLastError()。

示例:

WSADATA wsData;
int nRet=WSAStartup(MAKEWORD(2,2),&wsData);
if(nRet!=0)
{
	return nRet;
}

申请监听套接字

WINSOCK_API_LINKAGE SOCKET WSAAPI socket(
int af,
int type,
int protocol
);
备注:af 主要指IP的类型,常用的有:AF_INET(ip4) 、AF_INET6(ip6)
type 是通信类型 ,常用是:SOCK_DGRAM(UDP)、SOCK_STREAM(TCP)
protocol:是指通信协议,常用IPPROTO_TCP和IPPROTO_UDP,一般写成 0
返回值:成功返回一个Socket ,失败返回值为INVALID_SOCKET,可以调用WSAGetLastError()函数获取返错误码。

示例:

SOCKET  sock = socket(AF_INET, SOCK_DGRAM, 0);

    if (sock==INVALID_SOCKET)
    {
        return WSAGetLastError();
    }

初始地址结构体

    sockaddr_in sa,recSa;

    int len = sizeof(sa);

    sa.sin_addr.S_un.S_addr = INADDR_ANY;

    sa.sin_family = AF_INET;
    sa.sin_port = htons(9999);

绑定监听套接字

int WSAAPI bind(
SOCKET s,
const sockaddr *name,
int namelen
);
返回值:成功返回 0,失败返回SOCKET_ERROR,调用WSAGetLastError()函数获取返错误码。

示例:

int ret=bind(sock, (sockaddr*)&sa, len);
if(ret==SOCKET_ERROR)
{
	return WSAGetLastError();
}

接收数据

int WSAAPI recvfrom(
SOCKET s,
__out_data_source(NETWORK) char *buf,
int len,
int flags,
sockaddr *from,
int *fromlen
);
备注: s 是监听套接字
buf 是接收数据的缓冲区
*from 是一个新的地址结构体,存储发送端的ip和端口信息
*fromlen 地址结构体的长度指针

返回值:成功返回是接收长度,返回 0表示对方连接已经关闭(UDP不涉及),否则返回一个SOCKET_ERROR

示例:

char buf[1024];
memset(buf, 0, 1024);
int nlen = recvfrom(sock, buf, 1024, 0, (sockaddr*)&recSa, &len);
if (nlen>0)
 {
 	 char sIP[20]={0};
 	 inet_ntop(AF_INET, &recSa.sin_addr, sIP, 20);
 	 cout <<sIP<< buf << endl;
   //inet_ntoa(recSa.sin_addr) vs2019 这个函数不安全,不推荐使用
 }

注意:使用inet_ntop() 这个函数需要添加头文件
#include <WS2tcpip.h>

发送数据

int WSAAPI sendto(
SOCKET s,
const char *buf,
int len,
int flags,
const sockaddr *to,
int tolen
);
备注:s 申请的通讯套接字
*buf 要发送的缓冲区
len 发送的长度
flags 调用的方式,一般写为 0
*to 目的地址指针
tolen 地址结构长度
返回值 :成功返回发送的长度,失败返回 SOCKET_ERROR

示例:

memset(sendBuf, 0, sizeof(sendBuf));
cout << "pelase input word:";
cin.getline(sendBuf, 64);
sendto(psock, sendBuf, sizeof(sendBuf), 0, (sockaddr*)&sClient, len);
		

关闭套接字和套接字库

closesocket(sock);
WSACleanup();

接收端和发送端的区别

两者主要是发送端不需要进行绑定操作,其他基本上无差别,两者的全部代码如下:

接收端:

#include <iostream>

#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment (lib,"ws2_32.lib")
using namespace  std;

int main()
{
    WSADATA  wsData;

    int nret=WSAStartup(MAKEWORD(2, 2), &wsData);
    if(nret!=0)
    {
    	return nret;
    }
    
    sockaddr_in sa,recSa;

    int len = sizeof(sa);

    sa.sin_addr.S_un.S_addr = INADDR_ANY;

    sa.sin_family = AF_INET;
    sa.sin_port = htons(9999);

    SOCKET  sock = socket(AF_INET, SOCK_DGRAM, 0);

    if (sock==INVALID_SOCKET)
    {
        return WSAGetLastError();
    }

    bind(sock, (sockaddr*)&sa, len);

    while (true)
    {
        char buf[1024];

        memset(buf, 0, 1024);

        int nlen = recvfrom(sock, buf, 1024, 0, (sockaddr*)&recSa, &len);

        if (nlen>0)
        {
			char sIP[20];
			inet_ntop(AF_INET, &recSa.sin_addr, sIP, 20);
            //inet_ntoa(recSa.sin_addr);
            cout << sIP<<buf << endl;
        }

    }
   
}

发送端:

// Client_UDP.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <WS2tcpip.h>

using namespace std;

#pragma comment(lib,"ws2_32.lib")



int main()
{

	WSADATA wdata;

	WORD wVersion;

	wVersion = MAKEWORD(2, 2);

	WSAStartup(wVersion, &wdata);

	if (HIBYTE(wdata.wVersion) != 2 || LOBYTE(wdata.wVersion) != 2)
	{
		return -1;
	}

	sockaddr_in sClient;

	sClient.sin_family = AF_INET;
	sClient.sin_port = htons(9999);

	inet_pton(AF_INET, "127.0.0.1", &sClient.sin_addr);

	SOCKET psock = socket(AF_INET, SOCK_DGRAM, 0);

	int len = sizeof(sClient);

	char sendBuf[128];
	while (1)
	{

		memset(sendBuf, 0, sizeof(sendBuf));

		cout << "pelase input word:";

		cin.getline(sendBuf, 64);
		sendto(psock, sendBuf, sizeof(sendBuf), 0, (sockaddr*)&sClient, len);
	
	}
	return 0;
   
}



在Ubuntu系统上使用C++进行UDP通信通常涉及以下几个步骤: 1. **包含头文件**: 首先,你需要在代码中包含`<iostream>`、`<string>`以及`<boost/asio.hpp>`,其中`boost`库是用于网络通信的常用库。 ```cpp #include <iostream> #include <string> #include <boost/asio.hpp> ``` 2. **设置异步IO上下文**: 使用`io_context`创建一个异步I/O服务,这是处理网络事件的基础。 ```cpp boost::asio::io_context io_context; ``` 3. **定义套接字**: 创建一个UDP套接字,使用`ip::udp::endpoint`指定远程主机和端口。 ```cpp boost::asio::ip::udp::socket socket(io_context); boost::asio::ip::udp::endpoint remote_endpoint("your.remote.ip", your.remote.port); ``` 4. **发送数据**: 使用`send_to()`函数发送UDP数据包到指定地址。 ```cpp std::string message = "Hello, UDP!"; auto send_future = socket.async_send_to( boost::asio::buffer(message), remote_endpoint, // 发送完成的回调 [&, result = std::move(send_future)](const boost::system::error_code& error, std::size_t bytes_transferred) { if (!error) std::cout << "Sent " << bytes_transferred << " bytes to " << remote_endpoint.address() << ":" << remote_endpoint.port() << std::endl; else std::cerr << "Error sending data: " << error.message() << std::endl; }); ``` 5. **接收数据**: 如果需要接收数据,可以设置一个接受事件监听器。 ```cpp // 接收缓冲区 std::array<char, 1024> receive_buffer; // 接收数据的回调 void on_receive(const boost::system::error_code& error, size_t bytes_transferred) { if (error == boost::asio::error::message_size_exceeded) std::cerr << "Message too large." << std::endl; else if (error) { std::cerr << "Error receiving data: " << error.message() << std::endl; } else { std::cout << "Received " << bytes_transferred << " bytes from " << remote_endpoint.address() << ":" << remote_endpoint.port() << ". Message: " << std::string(receive_buffer.data(), bytes_transferred) << std::endl; } } // 启动接收操作 socket.async_recv_from( boost::asio::buffer(receive_buffer), remote_endpoint, on_receive ); ``` 6. **启动异步IO循环**: 最后,启动异步I/O服务,使其开始处理网络事件。 ```cpp io_context.run(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值