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;
   
}



  • 7
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值