网络编程 C++ Windows

在这里插入图片描述

网络编程 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的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值