软件开发——Socket实现底层UDP通信

第一次写东西,不周之处还请指正~

一、socket实现流程

图1. UDP通信流程
UDP通信仅需要绑定端口号就可以开始客户端和服务器之间的通信。

二、 C++实现连接的函数及用法

函数的参数说明什么的感觉百度还可以。。
https://baike.baidu.com/item/socket/281150?fr=aladdin

1、创建Socket

SOCKET sclient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

2、绑定端口

sockaddr_in sin;
		sin.sin_family = AF_INET;
		sin.sin_port = htons(8888);
		void* Address = &sin.sin_addr.S_un.S_addr;
		inet_pton(AF_INET, "127.0.0.1", Address);//本机地址
		int len = sizeof(sin);

3、收发数据

//定义发送缓冲区
		unsigned char data[Frame_length];
//发送数据
		const char * sendData = (char*)data;
		sendto(sclient, sendData, Frame_length, 0, (sockaddr *)&sin, len);
//定义接收缓冲区
		unsigned char recvData[Frame_length]; 
//接收数据
		int ret = recvfrom(sclient, (char*)recvData, Frame_length, 0, (sockaddr *)&sin, &len);

三、举个栗子~

几点说明:
(1)记的引用winsock相关的库;
(2)sendto、recvfrom参数类型要求比较严格,不同类型数据收发时需要转换或者拷贝到缓冲区里;
(3)下面的例子实现了双向的UDP通信,客户端向服务器发送结构体中信息(代表数据帧),服务器向客户端返回字符串;
(4)程序运行时需要在属性里关闭SDL检查
在这里插入图片描述

代码是临时写的一个例子,只为说明实现机制,举例可能不太恰当,还请见谅~
先看下结果:
在这里插入图片描述
代码如下:

1.客户端

#include "pch.h"
#include <stdio.h> 
#include <winsock2.h> 
#include <string>
#include <iostream>
#include <stdlib.h>
#include <WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")

using namespace std;
#define Frame_length 10

struct Packet {
	unsigned char number;
	unsigned char score;
}StuInf;

int main()
{
	while (1) {
		//给结构体赋值,也就是数据帧组帧
		int Stu_Number;
		cout << "请输入学号(1/2/3):";
		cin >> Stu_Number;
		if (Stu_Number == 1) {
			StuInf.number = 1;
			StuInf.score = 100;
		}
		else if (Stu_Number == 2) {
			StuInf.number = 2;
			StuInf.score = 99;
		}
		else if (Stu_Number == 3) {
			StuInf.number = 3;
			StuInf.score = 98;
		}
		//初始化WSA
		WORD socketVersion = MAKEWORD(2, 2);
		WSADATA wsaData;
		if (WSAStartup(socketVersion, &wsaData) != 0)
		{
			return 0;
		}

		//创建Socket
		SOCKET sclient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		/*
		AF_INET:32位IPv4地址+16位端口号;
		SOCK_DGRAM:UDP方式;
		IPPROTO_UDP:UDP协议。
		*/
		if (sclient == INVALID_SOCKET)
		{
			printf("invalid socket!");
			return 0;
		}

		//绑定IP和端口
		sockaddr_in sin;
		sin.sin_family = AF_INET;
		sin.sin_port = htons(8888);
		void* Address = &sin.sin_addr.S_un.S_addr;
		inet_pton(AF_INET, "127.0.0.1", Address);//本机地址
		int len = sizeof(sin);

		//定义发送数据缓冲区
		unsigned char data[Frame_length];//定义数组之后最好memset一下,不然可能会有各种乱七八糟的乱码

		//将结构体拷贝到字符数组中
		void const *p = &StuInf;//指向结构体的指针
		memset(data, 0, sizeof(data));//清零
		memcpy(data, p, sizeof(StuInf));//拷贝
		/*参数类型需要注意
		目标指针参数类型为void*
		源指针参数类型为void const*
		*/


		//发送数据
		const char * sendData = (char*)data;
		sendto(sclient, sendData, Frame_length, 0, (sockaddr *)&sin, len);
		//sendto参数类型同样需要注意

		//定义接收缓冲区
		unsigned char recvData[Frame_length]; 
		//接收数据
		memset(recvData, 0, sizeof(recvData));
		int ret = recvfrom(sclient, (char*)recvData, Frame_length, 0, (sockaddr *)&sin, &len);
		if (ret >= 0)
		{
			cout << recvData;
			cout << endl;
		}
		//释放连接
		closesocket(sclient);

		WSACleanup();
	}
}

2.服务器

#include "pch.h"
#include <iostream>
#include <stdio.h> 
#include <stdlib.h>
#include <winsock2.h> 

using namespace std;
#pragma comment(lib,"ws2_32.lib") 

#define Frame_length 10

int main()
{
	//初始化WSA
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 2);
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}

	//创建Socket
	SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);  //UDP
	if (serSocket == INVALID_SOCKET)
	{
		printf("socket error !");
		return 0;
	}

	//绑定IP和端口
	sockaddr_in serAddr;
	serAddr.sin_family = AF_INET; // IPV4(32位)与端口号(12位)组合
	serAddr.sin_port = htons(8888); // 端口号
	serAddr.sin_addr.S_un.S_addr = INADDR_ANY; //任意地址
	if (bind(serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
	{
		printf("bind error !");
		closesocket(serSocket);
		return 0;
	}

	sockaddr_in remoteAddr;
	int nAddrLen = sizeof(remoteAddr);

	// UDP没有listen()和accept()

	while (1)
	{
		//接收客户端发来的数据
		printf("等待接收...\n");
		unsigned char recvData[Frame_length]; //客户端发来的数据存在这个字符数组里
		memset(recvData, 0, sizeof(recvData));//初始化接收的数组
		int ret = recvfrom(serSocket, (char*)recvData, Frame_length, 0, (sockaddr*)&remoteAddr, &nAddrLen); 
		if (ret >= 0) //判断是否从客户端接收到数据
		{
			cout << "接收到数据帧:";
			for (int i = 0; i < Frame_length; i++)
			{
				printf("%02d ", recvData[i]);
			}
			cout << endl;
			int number = recvData[0];
			int score = recvData[1];
			cout << "学生学号为:" << number << endl
				<< "学生成绩为:" << score << endl;
		}
		else printf("接收失败");

		cout << endl;

		//向客户端返回数据
		const char* sendData = "已收到!";
		sendto(serSocket, sendData, Frame_length, 0, (sockaddr *)&remoteAddr, nAddrLen); 
	}

	// 关闭连接
	closesocket(serSocket);

	WSACleanup();
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值