在这里插入图片描述
网络编程 C++ Windows
一.网络编程的基本概念
有网络就要有Socket
Socket的定义
C/S模式
IP地址和端口
TCP/UDP
数据边界意思是:比如左边的人传给右边的人一百个数据,右边的人不管分几次收到,只关心有没有收到100个数据;接受的数据是由接收的人定的而不是发送的人决定。
二.网络编程的基本函数
套接字类型与协议设置
SOCK_STREAM[流套接字]
面向连接、可靠的数据传输适合传输大量的数据,不支持广播、多播 (TCP用)
SOCK_DGRAM[数据包套接字]
无连接支持广播、多播 (UDP用)
SOCK_RAW[原始套接字]
可以读写内核没有处理的IP数据报
避开TCP/IP处理机制,被传送的数据报可以被直接传送给需要它的的应用程序
-引用头文件winsock2.h
-导入ws2_32.lib库
-window下socket编程都要首先进行Winsock的初始化(Linux下不需要)
网络编程的基本函数和数据结构
函数的作用后面会讲的
上面的数据结构是是计算机用的,后面数据结构是程序员用的。大小都是16个字节 第一个是协议族,是ipv4还是ipv6;
TCP编程 服务器端
TCP套接字
TCPServer:
Windows 下开发需要初始化网络库 Linux下不需要初始化网络库
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main()
{
cout << "TCPServer Start!!!" << endl;
//0 初始化网络化库
WORD WVersionRequested;
WSADATA wsaData;
int err;
WVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(WVersionRequested, &wsaData);
if (err != 0)
{
printf("WSAStartup errorNum = %d\n", GetLastError());
return err;
}
if (LOBYTE(wsaData.wVersion) != 2,HIBYTE(wsaData.wVersion) != 2)
{
printf("LOBYTE errorNum = %d\n", GetLastError());
WSACleanup();
return -1;
}
//1 建立socket(安装电话机)
SOCKET socketServer = socket(AF_INET, SOCK_STREAM, 0);
//2 分配电话号码 设置参数
SOCKADDR_IN addrSrv;
addrSrv.sin_family = AF_INET;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_port = (6000);
if (SOCKET_ERROR== bind(socketServer, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
{
printf("bind errorNo=%d\n", GetLastError());
return -1;
}
//3 监听
if (SOCKET_ERROR== listen(socketServer, 5))
{
printf("listen errorNo=%d\n", GetLastError());
return -1;
}
SOCKADDR_IN addrCli;
int len = sizeof(addrCli);
while (TRUE)
{
//4 分配电话分机
printf("start accept\n");
SOCKET sockConn = accept(socketServer, (SOCKADDR*)&addrCli, &len);
printf("end accept\n");
char sendBuf[100] = {0};
//sprintf_s(sendBuf, 100, "hello");
sprintf_s(sendBuf, 100, "Welcome %s to China!!", inet_ntoa(addrCli.sin_addr));
//5 开始通话 进行收发数据
int iLen=send(sockConn, sendBuf, sizeof(sendBuf), 0);
char recvBuf[100] = {0};
iLen = recv(sockConn, recvBuf, 100, 0);
printf("RecvBuf=%s\n", recvBuf);
//6 关闭分机
closesocket(sockConn);
}
// 7 关闭总机
closesocket(socketServer);
WSACleanup();
system("pause");
return 0;
}
函数解释
1.socket
SOCKET WSAAPI socket(
[in] int af,
[in] int type,
[in] int protocol
);
af:
type:
protocol:
最后一个按照默认的0写就对了,初学者。
返回值
如果未发生错误, 套接字 将返回引用新套接字的描述符。 否则,将返回值 INVALID_SOCKET,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
2.htonl
htonl函数可用于将主机字节顺序中的IPv4地址转换为网络字节顺序中的IPv4地址。此函数不会执行任何检查来确定hostlong参数是否为有效的IPv4地址。
#define INADDR_ANY (ULONG)0x00000000
3.bind
int WSAAPI bind(
[in] SOCKET s,
[in] const sockaddr *name,
[in] int namelen
);
s:
标识未绑定套接字的描述符。(要绑定的套戒指)
name:
指向要分配给绑定套接字 的本地地址 的 sockaddr 结构的指针。
namelen:
name 参数指向的值的长度(以字节为单位)。
返回值
如果未发生错误, 绑定 将返回零。 否则,它将返回SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
4.listen
int WSAAPI listen(
[in] SOCKET s,
[in] int backlog
);
s:
标识绑定的未连接的套接字的描述符。
backlog:
挂起的连接队列的最大长度。 如果设置为 SOMAXCONN,则负责套接字 的基础 服务提供商会将积压工作设置为最大合理值。 如果设置为 SOMAXCONN_HINT (N) (其中 N 为数字) ,则积压工作值为 N,调整为在 200、65535) (范围内。 请注意, SOMAXCONN_HINT 可用于将积压工作设置为比 SOMAXCONN 更大的值。
返回值
如果未发生错误, 则侦听 返回零。 否则,将返回 值 SOCKET_ERROR ,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
5.accept
SOCKET WSAAPI accept(
[in] SOCKET s,
[out] sockaddr *addr,
[in, out] int *addrlen
);
参数
[in] s
一个描述符,用于标识已使用 侦 听函数置于侦听状态的套接字。 连接实际上是使用 accept 返回的套接字建立的。(创建的分机的socket存放的变量)
[out] addr
指向接收连接实体地址的缓冲区的可选指针,该地址称为通信层。 addr 参数的确切格式由创建 sockaddr 结构中的套接字时建立的地址系列确定。(接受的分机的地址的结构体)
[in, out] addrlen
指向包含 addr 参数指向的结构长度的整数的可选指针。
返回值
如果未发生错误, 则 accept 将返回 类型为 SOCKET 的值,该值是新套接字的描述符。 此返回值是建立实际连接的套接字的句柄。
否则,将返回 值 INVALID_SOCKET ,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
addrlen 引用的整数最初包含 addr 指向的空间量。返回时,它将包含返回的地址的实际长度(以字节为单位)。
6.send
int WSAAPI send(
[in] SOCKET s,
[in] const char *buf,
[in] int len,
[in] int flags
);
参数
[in] s
标识已连接套接字的描述符。(要发送的客户的socket)
[in] buf
指向包含要传输的数据的缓冲区的指针。
[in] len
buf 参数指向的缓冲区中数据的长度(以字节为单位)。
[in] flags
一组指定调用方式的标志。 此参数是使用以下任一值的按位 OR 运算符构造的。
返回值
如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 在 len 参数中请求发送的字节数。 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
7.recv
int WSAAPI recv(
[in] SOCKET s,
[out] char *buf,
[in] int len,
[in] int flags
);
参数
[in] s
标识连接的套接字的描述符。 (要接受那个客户的socket)
[out] buf
指向用于接收传入数据的缓冲区的指针。
[in] len
buf 参数指向的缓冲区的长度(以字节为单位)。
[in] flags
影响此函数行为的一组标志。 请参阅下面的备注。 有关此参数的可能值的详细信息,请参阅“备注”部分。(看不懂 默认0)
返回值
如果未发生错误, recv 将返回收到的字节数, buf 参数指向的缓冲区将包含接收的此数据。 如果连接已正常关闭,则返回值为零。
否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
8.closesocket
int WSAAPI closesocket(
[in] SOCKET s
);
参数
[in] s
标识要关闭的套接字的描述符。 (要关闭的套接字)
返回值
如果未发生错误, 则 closesocket 返回零。 否则,将返回 值 SOCKET_ERROR ,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
9.inet_ntoa
作用:inet_ntoa 函数将 internet 网络地址) (Ipv4 转换为 Internet 标准点十进制格式的 ASCII 字符串。
char *WSAAPI inet_ntoa(
in_addr in
);
返回值
如果未发生错误, inet_ntoa 返回指向静态缓冲区的字符指针,该缓冲区包含标准“.”中的文本地址 符号。 否则,它将返回 NULL。
TCPClient:
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main()
{
cout << "TCPClient Start!!!" << endl;
//0 初始化网络化库
WORD WVersionRequested;
WSADATA wsaData;
int err;
WVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(WVersionRequested, &wsaData);
if (err != 0)
{
printf("WSAStartup errorNum = %d\n", GetLastError());
return err;
}
if (LOBYTE(wsaData.wVersion) != 2, HIBYTE(wsaData.wVersion) != 2)
{
printf("LOBYTE errorNum = %d\n", GetLastError());
WSACleanup();
return -1;
}
//1 建立socket(安装电话机)
SOCKET socketCli = socket(AF_INET, SOCK_STREAM, 0);
//2 配置要链接的服务器 设置参数
SOCKADDR_IN addrSrv;
addrSrv.sin_family = AF_INET;
addrSrv.sin_addr.S_un.S_addr = inet_addr("用你要链接的ipv4地址");
addrSrv.sin_port = (6000);
//3 连接服务器
if (SOCKET_ERROR==connect(socketCli,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)))
{
printf("connect errorNo=%d\n", GetLastError());
return -1;
}
//4 收发数据
char recvBuf[100] = { 0 };
int iLen = recv(socketCli, recvBuf, 100, 0);
printf("recvBuf=%s", recvBuf);
char sendBuf[100] = "我是sb";
iLen = send(socketCli, sendBuf, 100, 0);
//5 关闭套接字
closesocket(socketCli);
WSACleanup();
system("pause");
return 0;
}
1.connect
int WSAAPI connect(
[in] SOCKET s,
[in] const sockaddr *name,
[in] int namelen
);
参数
[in] s
标识未连接的套接字的描述符。
[in] name
指向应建立连接的 sockaddr 结构的指针。
[in] namelen
name 参数指向的 sockaddr 结构的长度(以字节为单位)。
返回值
如果未发生错误, 则连接 返回零。 否则,它将返回SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
2.inet_addr
unsigned long WSAAPI inet_addr(
const char *cp
);
cp:
inet_addr 函数解释 cp 参数指定的字符串。 此字符串表示以 Internet 标准“.”表示的数字 Internet 地址。 符号。 返回的值是一个适合用作 Internet 地址的数字。 所有 Internet 地址都按 IP 的网络顺序返回 (字节从左到右) 。 如果将“” (空格) 传入 inet_addr 函数, inet_addr 返回零。
返回值
如果未发生错误, inet_addr 函数将返回一个无符号长值,其中包含给定的 Internet 地址的合适二进制表示形式。
如果 cp 参数中的字符串不包含合法的 Internet 地址,例如,如果“a.b.c.d”地址的一部分超过 255,则 inet_addr 返回 INADDR_NONE的值。