第一次写东西,不周之处还请指正~
一、socket实现流程
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;
}