基础网络编程——UDP编程

网络编程

UDP 编程和 TCP编程的区别:

  • TCP是面向连接的,UDP是无连接的

  • TCP是可靠的,UDP是不可靠的

  • TCP是面向字节流的,UDP是面向数据报文的

  • TCP只支持点对点通信,UDP支持一对一,一对多,多对多

 TCP编程 可以看这个。

由于 UDP 是无连接的,而且是不可靠的,和 TCP 相比,并不需要建立连接,所有 UDP 只需要知道往哪里发,直接发送就好。

1、UDP 编程

1.1、前期准备
#include <WinSock32.h>					// 包含头文件
#pragma comment(lib, "ws2_32.lib")		// 添加静态链接库

int main() {
    // 网络环境初始化
    WSADATA data;
    WORD virsion = MAKEWORD(2, 2);
    
    int err = WSAStartup(virsion, &data);
    
    if (err != 0)
    {
        printf("WSAStartup errorNum = %d", err);
        return err;
    }
    
    if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
    {
        printf("LOBYTE errorNum = %d", GetLastError());
        WSACleanup();
        return -1;
    }
    
    WSACleanup();		// 清除网络环境
}

1.2、服务器编程
1.2.1、示例代码
int main() {

	// 一、初始化网络环境
	....;

	// 二、创建服务器
	SOCKET sockSer = socket(AF_INET, SOCK_DGRAM, 0);

	if (sockSer == INVALID_SOCKET)
	{
		printf("socket errorNum = %d\n", GetLastError());
		return -1;
	}

	// 三、配置网络地址和端口号
	SOCKADDR_IN addrSer = {};
	addrSer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSer.sin_family = AF_INET;		// 始终设置为 AF_INET
	addrSer.sin_port = htons(5201);

	// 四、绑定网络地址和端口号
	if (SOCKET_ERROR == bind(sockSer, (SOCKADDR*)&addrSer, sizeof(SOCKADDR)))
	{
		printf("bind errorNum = %d\n", GetLastError());
		return -1;
	}

	SOCKADDR_IN addrCli = {};
	int len = sizeof(SOCKADDR_IN);
	char recvBuff[100] = { 0 };		// 接收数据
	char sendBuff[100] = { 0 };		// 发送数据
	int iLen = 0;					// 接收的数据数

	// 五、循环发送数据
	while (TRUE)
	{
		iLen = recvfrom(sockSer, recvBuff, 100, 0, (SOCKADDR*)&addrCli, &len);
		if (iLen == SOCKET_ERROR)
		{
			printf("recvfrom errorNum = %d\n", GetLastError());
			return -1;
		}
		else if (iLen == 0) break;		// 正常关闭连接,退出循环
		printf_s("%s\n", recvBuff);		// 正常接收,打印信息

		// 在 sendBuff 中配置要发送的信息

		iLen = sendto(sockSer, sendBuff, strlen(sendBuff), 0, (SOCKADDR*)&addrCli, len);
		if (iLen == SOCKET_ERROR)
		{
			printf("sendto errorNum = %d\n", GetLastError());
			return -1;
		}
	}

	// 六、关闭连接
	closesocket(sockSer);
	WSACleanup();

	return 0;
}

1.2.2、主要函数
  • 创建服务器套接字:socket()

SOCKET WSAAPI socket(int af, int type, int protocol );

第一个参数为 地址系列规范,使用IPv4 为 AF_INET,使用IPv6为AF_INET6

第二个参数为 套接字的类型规范,地址系列为为IPv4或IPv6的情况下,TCP协议则为SOCK_STREAM,UDP协议为SOCK_DGRAM

第三个参数为 要使用的协议,为 0 则调用方不希望指定协议,服务提供商将选择要使用的 协议

  • 绑定本机 IP 和端口:bind()

int bind(

SOCKET s,                   // 创建的socket

sockaddr * name,         // 包含地址和端口的结构体

int namelen                  // sockaddr 结构长度

);

// 返回值:返回SOCKET_ERROR失败,该宏被定义为-1,否则成功,返回值为0

  • 发送信息:sendto()

  • 接收信息:recvfrom()

int sendto(

SOCKET s,

const char *buf,          // 要发送的数据

int len,                        // 内容长度

int flags,                     // 一般为0

const sockaddr *to,   // 要发送的网络地址和端口信息

int tolen                     // 由 to 参数指向的地址的大小

);

// 返回值:宏SOCKET_ERROR 表示发送失败,否则返回发送成功的字节数

int recvfrom(

SOCKET s,               // 套接字

char *buf,                  // 接受数据的缓存区

int len,                       // 缓存区大小

int flags,                    // 标志,一般填0

sockaddr *from,        // 要接收的网络地址和端口信息

int *fromlen               // 由 from 参数指向的地址的大小

);

// 如果未发生错误, recvfrom 将返回收到的字节数。 如果连接已正常关闭,则返回值为零。 否则,将返回值 SOCKET_ERROR

  • 网络环境初始化:WSAStartup()

  • 关闭 socket :closesocket()

  • 清除网络环境:WSACleanup()

1.3、客户端编程
1.3.1、示例代码
int main()
{

	// 一、初始化网络环境
	// ....;

	// 二、创建服务器
	SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0);

	if (sockCli == INVALID_SOCKET)
	{
		printf("socket errorNum = %d\n", GetLastError());
		return -1;
	}

	// 三、配置要发送到的网络地址和端口号
	SOCKADDR_IN addrCli = {};
	inet_pton(AF_INET, "127.0.0.1", &addrCli);	// 使用网络回环地址
	addrCli.sin_family = AF_INET;		// 始终设置为 AF_INET
	addrCli.sin_port = htons(5201);
	int len = sizeof(SOCKADDR);

	int iLen = 0;					// 接收的数据数
	char sendBuff[100] = { 0 };		// 发送数据
	char recvBuff[100] = { 0 };		// 接收数据

	// 四、发送数据
    // 在 sendBuff 中配置要发送的数据
	iLen = sendto(sockCli, sendBuff, 100, 0, (SOCKADDR*)&addrCli, len);
	if (iLen == SOCKET_ERROR)
	{
		printf("sendto errorNum = %d\n", GetLastError());
		return -1;
	}
	printf("send: %s\n", sendBuff);

	// 五、接收数据
	iLen = recvfrom(sockCli, recvBuff, 100, 0, (SOCKADDR*)&addrCli, &len);
	if (iLen == SOCKET_ERROR)
	{
		printf("recvfrom errorNum = %d\n", GetLastError());
		return -1;
	}
	printf("recv: %s\n", recvBuff);

	system("pause");
	return 0;
}

1.3.2、主要函数

2.2.2、主要函数中均出现过

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值