网络编程基础

  1. 基础概念
    1. ip地址
    2. 端口word
    3. 公网 局域网
    4. 两个架构
  2. udp
    1. socket
      1. 服务器端
      2. 客户端
    2. udp聊天室
      1. 功能

基础概念

协议 - 约定好的数据格式,约定好的数据的解析格式

比如说我现在要从A发送 到B 数据, 一次性肯定发不完 那么我们就 分组发送:第一个4字节给个大小,后面4个字节跟着是数据,按照这样的数据格式,这就是自己定了一个协议

ip地址

那此时有很多台电脑 要从A发到B 再发到E 他怎么知道要发给E?

这就是需要IP地址 通常是IPV4是四个字节

别的电脑怎么知道你这个地址呢?

这个电脑会经常性的向外部发数据 ,数据里面包含mac 地址和自己的ip地址

端口word

我们这个电脑上开了很多进程,好多进程要去连网,当你数据到达了自己的电脑,那要给哪个进程去处理,给一个word标识,叫端口,有些端口不要去用 比如说80,443 ,50 8080 这些都是预定好1的

比如说80端口 给服务器用,443给tcp的ssl使用的

公网 局域网

我们都知道 电脑 手机连到路由上面,路由连接到网络上 叫公网

通过路由连接到家里 公司里的叫局域网,这些IP地址是由路由去分配的,别人发数据都是通过路由转换 到我们自己的电脑上去,我们发数据也是过路由 在网上兜兜转转进别人家的路由

我们打开cmd 输入ipconfig 查看的ipv4 是局域网,打卡百度输入IP138 查询我们的ip 那是公网

两个架构

服务器客户端 c/S client server 架构

B/S - browser server 浏览器 服务器

udp

又叫网络编程 - socket编程 - 套接字编程

步骤:

  1. 创建socket,指定使用的协议

  2. 绑定端口

  3. 发送数据

  4. 接受数据

  5. 关闭socket

socket

1
2
3
4
5
6
SOCKET socket(
int af, // AF_INET - tcp/ip
int type, //指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。

int protocol //指定协议,故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议
);

我们先打开VS 创建两个控制台空应用

服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <iostream>
using namespace std;

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Winsock2.h>
#pragma comment(lib, "Ws2_32.lib")

void InitWs2();
void UninitWs32();

int main()
{
InitWs2();

//1) 创建socket
SOCKET sockServer = socket(
AF_INET, //ipv4地址簇
SOCK_DGRAM, //数据报
IPPROTO_UDP);//udp协议
if (sockServer == INVALID_SOCKET)
{
printf("socket 创建失败 \r\n");
return 0;
}
else
{
printf("socket 创建socket成功 \r\n");
}

//(2)绑定端口 127.0.0.1 回环地址 发送过去的数据会返回来
sockaddr_in siServer;
siServer.sin_family = AF_INET;
siServer.sin_port = htons(0x9527);//127是16进制7F
//小尾转大尾 host to net short ntoh,网络编程是大端
siServer.sin_addr.S_un.S_addr =
//0x0100007f;//大尾
inet_addr("127.0.0.1");
//inet_addr是将一个点分十进制的IP转换成一个长整型数(u_long类型)
//0x7f000001;
int nRet = bind(sockServer, (sockaddr*)&siServer, sizeof(siServer));
// bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。
if (nRet == SOCKET_ERROR)
{
printf("绑定地址失败 \r\n");
return 0;
}
else
{
printf("绑定地址成功 \r\n");
}

//3.收数据

sockaddr_in siClient = {0};
int nLen = sizeof(siClient);
char szBuff[MAXBYTE] = {0};
nRet = recvfrom(sockServer, //句柄
szBuff, sizeof(szBuff), //接受数据缓冲区
0,//标志
(sockaddr*)&siClient, &nLen//发送来的数据的地址
);
if (nRet == 0 || nRet == SOCKET_ERROR)
{
printf("接受数据失败\r\n");
return 0;
}
else {
printf("受到来自:%s:%d的数据:%s \r\n",
inet_ntoa(siClient.sin_addr), //将一个十进制网络字节序转换为点分十进制IP格式的字符串。
ntohs(siClient.sin_port), //ntohs()是一个函数名,作用是将一个16位数由网络字节顺序转换为主机字节顺序(大尾转小尾)
szBuff);

}
//4.发送数据
char szSend[] = {"recv OK!"};
nRet = sendto(sockServer,
szSend, sizeof(szSend),
0,
(sockaddr*)&siClient, sizeof(siClient));
if (nRet == SOCKET_ERROR)
{
printf("发送数据失败 \r\n");
}
else
{
printf("回复数据到:%s:%d的数据:%s \r\n",
inet_ntoa(siClient.sin_addr),
ntohs(siClient.sin_port),
szSend);
}

closesocket(sockServer);
std::cout << "Hello World!\n";
}


void InitWs2()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;

wVersionRequested = MAKEWORD(2, 2);

err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return;
}

/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */

if (LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
WSACleanup();
return;
}

/* The WinSock DLL is acceptable. Proceed. */
}

void UninitWs32()
{
WSACleanup(); //WSACleanup()是一个计算机函数,功能是终止Winsock 2 DLL (Ws2_32.dll) 的使用,函数原型是int PASCAL FAR
}


客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <iostream>
using namespace std;

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Winsock2.h>
#pragma comment(lib, "Ws2_32.lib")

void InitWs2();
void UninitWs32();


int main()
{
InitWs2();

//1) 创建socket
SOCKET sockClient = socket(
AF_INET, //ipv4地址簇
SOCK_DGRAM, //数据报
IPPROTO_UDP);//udp协议
if (sockClient == INVALID_SOCKET)
{
printf("socket 创建失败 \r\n");
return 0;
}
else
{
printf("socket 创建socket成功 \r\n");
}

//发送数据
//sockaddr_in 结构体来处理网络通信的地址。
/* struct sockaddr_in{
short sin_family;
unsigned short sin_port;
IN_ADDR sin_addr;
char sin_zero[8];};
*/

sockaddr_in siServer;
siServer.sin_family = AF_INET;
siServer.sin_port = htons(0x9527);//小尾转大尾 host to net short ntoh
siServer.sin_addr.S_un.S_addr =
//0x0100007f;//大尾
inet_addr("127.0.0.1");
char szBuff[] = { "hello socket" };
int nRet = sendto(sockClient,
szBuff, sizeof(szBuff),
0,
(sockaddr*)&siServer, sizeof(siServer));
if (nRet == SOCKET_ERROR)
{
printf("发送数据失败 \r\n");
}
else
{
printf("发送数据完毕 \r\n");
}

sockaddr_in siRecv = { 0 };
int nLen = sizeof(siRecv);
char szRecv[MAXBYTE] = { 0 };
nRet = recvfrom(sockClient, //句柄
szRecv, sizeof(szRecv), //接受数据缓冲区
0,//标志
(sockaddr*)&siRecv, &nLen//发送来的数据的地址
);
if (nRet == 0 || nRet == SOCKET_ERROR)
{
printf("接受数据失败\r\n");
return 0;
}
else {
printf("受到来自:%s:%d的数据:%s \r\n",
inet_ntoa(siRecv.sin_addr),
ntohs(siRecv.sin_port),
szRecv);
}

std::cout << "Hello World!\n";
closesocket(sockClient);
UninitWs32();

}


void InitWs2()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;

wVersionRequested = MAKEWORD(2, 2);

err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return;
}

/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */

if (LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
WSACleanup();
return;
}

/* The WinSock DLL is acceptable. Proceed. */

}

void UninitWs32()
{
WSACleanup();
}

udp聊天室

功能

上线,下线, 客户端1,2,3上线 会告诉服务器 上线了,服务器再告诉 1,2,3其他客户端上线了

群聊 客户端1发给服务器 让服务器告诉其他

私聊 客户端1发给服务器 让服务器告诉2


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1204342476@qq.com

💰

×

Help us with donation