1、概念
-
网络通信如何识别通讯双方:(五元组) 一个本机IP对应自己的电脑,远程IP对应一个别人的电脑; 以及电脑有多个运行的程序,用端口号区分不同的程序 并且使用协议名最终确定 -
INADDR_ANY 泛指本机IP(即0.0.0.0) #define INADDR_ANY ? ? ? ? ? ? (ULONG)0x00000000 -
客户端和服务端的地址设置: 地址都是表明自己的,所以服务端必然是本机,客户端就是其他人电脑对应的IP
2、实现流程图
借用丙佬的图,顺便附上链接基于 UDP 的套接字通信 | 爱编程的大丙 (subingwen.cn)
(本质上我自己没有完成互相通讯,只有一个单向传播嘤嘤嘤)
3、代码分段解读(其实算是分功能)
-
/*初始化WSA*/
?
WSADATA data; ? ? ? ? ?//创建对象
int error = WSAStartup(MAKEWORD(2, 2), &data);//WSA 是windows socket api,这里创建一个对象?可以回来补充!;MAKEWORD(2,2)是使用version2.2的套接字
if (error != 0)
{
? ?printf("error\n");
? ?return 1;
}
//这里检查版本对不对,高字节是主版本,低字节是副版本
if (HIBYTE(data.wVersion) != 2 || LOBYTE(data.wVersion) != 2)
{
? ?WSACleanup();
? ?printf("version wrong\n");
? ?return 0;
} -
/*实例化SOCKET*/
?
SOCKET client_sock = socket(AF_INET, SOCK_DGRAM, 0);
?
//第一个是地址类型;第二个是套接字类型;第三个是要使用的通讯协议
//其他参数见官方doc
//https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket -
/*实例化SOCKADDR_IN*/
?
SOCKADDR_IN server_address;
?
//三个主要属性:1.sin_addr 表示socket收发地址,这是一个结构体;常见的有
server_address.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
//或者↓这下面的是wsa2.h的表达方式
inet_pton(AF_INET, "10.136.122.138", &server_address.sin_addr.S_un.S_addr);
// ? ? ? ? ? 2.sin_family 如果用socket编程,似乎只能用AF_INET
// ? ? ? ? ? 3.sin_port ? 表示该程序的端口号(自己找一个空闲的端口号),有需要对应htons函数
//具体举个例子
?
server_address.sin_family = AF_INET;
server_address.sin_port = htons(6666);
-
/*绑定套接字和地址*/
bind(server_sock, (SOCKADDR*)&server_address, sizeof(SOCKADDR)); -
/*初始化一些用于收发的存储量*/
int len = sizeof(SOCKADDR);
char ?send_buffer[100] = "abbbbb"; -
最后简单介绍一下sendto 和recvfrom 的用法 (1)函数原型 int WSAAPI sendto(
[in] SOCKET ? ? ? ? s,
[in] const char ? ? *buf,
[in] int ? ? ? ? ? ?len,
[in] int ? ? ? ? ? ?flags,
[in] const sockaddr *to,
[in] int ? ? ? ? ? ?tolen
);
?
//举个例子
?
sendto(client_sock, send_buffer, strlen(send_buffer) + 1, 0, (SOCKADDR*)&server_address, len);
//这个是客户端发给服务端的句子;第一项就是使用者端的套接字
// ? ? ? ? ? ? ? ? ? ? ? ? 第二项目是发送的字符串
// ? ? ? ? ? ? ? ? ? ? ? ? 第三项是这个字符串的长度
// ? ? ? ? ? ? ? ? ? ? ? ? 第四项俺也不太会,一般默认0
// ? ? ? ? ? ? ? ? ? ? ? ? 第五项是发送给的东西的地址,传参传sockaddr结构体的指针
// ? ? ? ? ? ? ? ? ? ? ? ? 第六项是这个sockaddr的大小;int len = sizeof(SOCKADDR); int WSAAPI recvfrom(
[in] ? ? ? ? ? ? ? ?SOCKET ? s,
[out] ? ? ? ? ? ? ? char ? ? *buf,
[in] ? ? ? ? ? ? ? ?int ? ? ?len,
[in] ? ? ? ? ? ? ? ?int ? ? ?flags,
[out] ? ? ? ? ? ? ? sockaddr *from,
[in, out, optional] int ? ? ?*fromlen
);
?
//举个例子
?
recvfrom(server_sock, recieve_buffer, sizeof(recieve_buffer), 0, (SOCKADDR*)&client_address, &len);
//这个是服务端接受客户端发送来的信息的例子;第一项是使用者的套接字
// ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 第二项是存信息的数组
// ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 第三项是这个数组长度
// ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 第四项同上,默认0吧
// ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 第五项是数据来源的地址,传的同样是sockaddr的指针
// ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 第六项同前
4、实现代码
(1)功能提醒:就是简单的客户端发,服务端收;这种最基础的都大同小异,可能得掌握bind、端口等具体含义与作用后拓展会更好(这只小菜狗想试着做个狼人杀系统,但是可能大概率寄)
(2)客户端
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string.h>
?
#pragma comment(lib, "Ws2_32.lib")
?
int main(void)
{
WSADATA data;
int error = WSAStartup(MAKEWORD(2, 2), &data);
if (error != 0)
{
printf("error\n");
return 1;
}
if (HIBYTE(data.wVersion) != 2 || LOBYTE(data.wVersion) != 2)
{
WSACleanup();
printf("version wrong?\n");
return 0;
}
?
SOCKET client_sock = socket(AF_INET, SOCK_DGRAM, 0);
?
//这里考虑去掉,晚上回来试试
SOCKADDR_IN client_address;
inet_pton(AF_INET, "10.136.210.98", &client_address.sin_addr.S_un.S_addr);//这里记得换一下,变成其他电脑的ip
client_address.sin_family = AF_INET;
client_address.sin_port = htons(6666);
//去掉↑
?
//手动加
SOCKADDR_IN server_address;
inet_pton(AF_INET, "我自己电脑(服务端)的ip", &server_address.sin_addr.S_un.S_addr);
server_address.sin_family = AF_INET;
server_address.sin_port = htons(6666);
?
?
int len = sizeof(SOCKADDR);
char ?send_buffer[100] = "abbbbb";
?
printf("Connection established,send \'#\' to disconnect.\n");
?
while (1)
{
puts("enter sth to send:");
gets_s(send_buffer);
?
?
sendto(client_sock, send_buffer, strlen(send_buffer) + 1, 0, (SOCKADDR*)&server_address, len);
?
?
}
closesocket(client_sock);
WSACleanup();
return 0;
}
(3)服务端
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
?
#pragma comment(lib, "Ws2_32.lib")
?
int main(void)
{
WSADATA data;
int error = WSAStartup(MAKEWORD(2, 2), &data);
if (error != 0)
{
printf("error\n");
return 1;
}
if (HIBYTE(data.wVersion) != 2 || LOBYTE(data.wVersion) != 2)
{
WSACleanup();
printf("version wrong?\n");
return 0;
}
?
SOCKET server_sock = socket(AF_INET, SOCK_DGRAM, 0);
?
SOCKADDR_IN server_address;
server_address.sin_addr.S_un.S_addr = inet_addr("我自己电脑的ip");
server_address.sin_family = AF_INET;
server_address.sin_port = htons(6666);
?
int flag = bind(server_sock, (SOCKADDR*)&server_address, sizeof(SOCKADDR));
if (flag == -1)
puts("eeee");
SOCKADDR_IN client_address;
//这里加进去的
client_address.sin_addr.S_un.S_addr = inet_addr("10.135.7.112");//这里记得换一下,变成其他电脑的ip
client_address.sin_family = AF_INET;
client_address.sin_port = htons(6666);
//这里加入
int len = sizeof(client_address);
char recieve_buffer[100], send_buffer[100] = "abbbbbbbbbbbbbbbbbb", tmp_buffer[30];
?
printf("Connection established,send \'#\' to disconnect.\n");
?
while (1)
{
recvfrom(server_sock, recieve_buffer, sizeof(recieve_buffer), 0, (SOCKADDR*)&client_address, &len);
puts("recieved\n");
printf("%s\n", recieve_buffer);
}
?
closesocket(server_sock);
WSACleanup();
?
return 0;
}
|