c++ 网络编程 基本交互与多线程交互

   提到网络编程我们首先想到的是socket,俗称套接字,他将端口和ip进行连接, 然后是winsock,是windows提供的一款网络编程接口。分为1和2两个版本,版本1只提供tcp和udp协议。

  tcp和udp是网络通讯基本协议,tcp协议需要三次招手,要求稳定的连接,如同和服务器要有夫妻的名分,udp直接发送到服务器,一夜情

  关于c++的网络编程,微软提供了进行操作的程序接口

  先说服务器端

  1. socket()
  2. bind()
  3. listen()
  4. accept()
  5. recv()/send()
  6. close()

   这就是大致流程,先创建套接字,连接ip和端口,开放访问,再是等待客户端的访问,然后接受访问,保存消息,发送反馈

//winsock是windows提供的一款网络编程接口。分为1和2两个版本,版本1只提供tcp和udp协议

//tcp协议需要稳定链接到服务器,所以说要三次招手
//udp直接打包到网络上发送,不需要链接
#include<WinSock2.h>
//windows.h需要在winsock下面包含
#include<Windows.h>
//网络分为cs和bs'两种模式,cs是客户端和服务器交互,bs是游览器和服务器交互

#include<iostream>

#pragma comment(lib,"ws2_32.lib")

#include<WS2tcpip.h>

int main()
{
	//1.初始化网络环境
	//第一个参数 sock版本号
	//WSAStartup(0X0202);
	WSADATA date{ 0 };
	WSAStartup(MAKEWORD(2,2),&date);

	//2 创建SOCKET
	//参数1 地址系列
	//参数二 套接类型
	//参数三 传输协议
	SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//3 绑定端口号和IP地址,让客户端可以链接
	//使用sockaddr_in结构体保存端口和ip
	sockaddr_in serverAddr{ 0 };
	serverAddr.sin_family = AF_INET;
	//绑定端口 需要用htons转换
	serverAddr.sin_port = htons(8888);
	
	//绑定ip地址
	inet_pton(AF_INET, "10.212.37.134", &serverAddr.sin_addr);

	//全部链接到服务器 
	//参数1 socket对象 参数2 sockaddr_in结构体地址转SOCKADDR 参数3 结构体大小
	bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr));


	//4 监听
	// 参数2 挂起的连接队列的最大长度。 如果设置为 SOMAXCONN,则负责套接字 的基础 服务提供商会将积压工作设置为最大合理值
	listen(server, SOMAXCONN);


	while (1)
	{

		//5 接受会话
		//客户地址

		sockaddr_in clientAddr{ 0 };

		int size = sizeof(clientAddr);
		
		printf("等待客户端连接中..........");

		//接收客户端
		//这是阻塞函数,直到等到客户端发送消息
		SOCKET client = accept(server, (SOCKADDR*)&clientAddr, &size);

		char buff[0x100]{ 0 };

		//保存客户端发送消息
		recv(client, buff, 0x100, 0);

		printf("客户端说:%s\n", buff);

		send(client, "收到消息", 20, 0);
	}

	closesocket(server);

	return 0;
}

这是简单的服务端

然后是客户端

  1. socket()
  2. connect()
  3. send()/recv()
  4. close()

创建套接字,绑定需要访问的服务器的ip和端口,发送消息,接受反馈,关闭客户端

//winsock是windows提供的一款网络编程接口。分为1和2两个版本,版本1只提供tcp和udp协议

//tcp协议需要稳定链接到服务器,所以说要三次招手
//udp直接打包到网络上发送,不需要链接
#include<WinSock2.h>
//windows.h需要在winsock下面包含
#include<Windows.h>
//网络分为cs和bs'两种模式,cs是客户端和服务器交互,bs是游览器和服务器交互

#include<iostream>

#pragma comment(lib,"ws2_32.lib")

#include<WS2tcpip.h>

int main()
{
	//1.初始化网络环境
	//第一个参数 sock版本号
	//WSAStartup(0X0202);
	WSADATA date{ 0 };
	WSAStartup(MAKEWORD(2, 2), &date);

	//2 创建SOCKET
	//参数1 地址系列
	//参数二 套接类型
	//参数三 传输协议
	SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//3 绑定端口号和IP地址,让客户端可以链接
	//使用sockaddr_in结构体保存端口和ip
	sockaddr_in serverAddr{ 0 };

	serverAddr.sin_family = AF_INET;
	//绑定端口 需要用htons转换
	serverAddr.sin_port = htons(8888);

	//绑定ip地址
	inet_pton(AF_INET, "10.212.37.134", &serverAddr.sin_addr);

	int ret = connect(client, (SOCKADDR*)(&serverAddr), sizeof(serverAddr));

	if (ret != 0)
	{
		printf("连接服务器失败");
	}

	//参数三 发送的输出指针缓冲区
	send(client, "客户端发送的消息", 16, 0);

	system("pause");




	return 0;

}

这是最简单的服务器和客户端交互,只能支持一对一的交互,那么如何让服务器支持多客户端多线程交互呢

多线程交互,多人聊天

服务器端


#include<WinSock2.h>
//windows.h需要在winsock下面包含
#include<Windows.h>
//网络分为cs和bs'两种模式,cs是客户端和服务器交互,bs是游览器和服务器交互

#include<iostream>

#pragma comment(lib,"ws2_32.lib")

#include<WS2tcpip.h>

#include<vector>
using std::vector;

//创建一个容器,存放SOCKET
vector<SOCKET> clientList;


DWORD WINAPI ThreadProc(
	_In_ LPVOID param
);



int main()
{
	//1.初始化网络环境
	//第一个参数 sock版本号
	//WSAStartup(0X0202);
	WSADATA date{ 0 };
	WSAStartup(MAKEWORD(2,2),&date);

	//2 创建SOCKET
	//参数1 地址系列
	//参数二 套接类型
	//参数三 传输协议
	SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//3 绑定端口号和IP地址,让客户端可以链接
	//使用sockaddr_in结构体保存端口和ip
	sockaddr_in serverAddr{ 0 };
	serverAddr.sin_family = AF_INET;
	//绑定端口 需要用htons转换
	serverAddr.sin_port = htons(8888);
	
	//绑定ip地址
	inet_pton(AF_INET, "10.212.37.134", &serverAddr.sin_addr);

	//全部链接到服务器 
	//参数1 socket对象 参数2 sockaddr_in结构体地址转SOCKADDR 参数3 结构体大小
	bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr));


	//4 监听
	// 参数2 挂起的连接队列的最大长度。 如果设置为 SOMAXCONN,则负责套接字 的基础 服务提供商会将积压工作设置为最大合理值
	listen(server, SOMAXCONN);


	while (1)
	{

		//5 接受会话
		//客户地址
		sockaddr_in clientAddr{ 0 };
		int size = sizeof(clientAddr);
		
		printf("等待客户端连接中..........");

		//接收客户端
		//这是阻塞函数,直到等到客户端发送消息
		SOCKET client = accept(server, (SOCKADDR*)&clientAddr, &size);

		//存储client 查看有多少人连接着服务器
		clientList.push_back(client);

		//创建线程
		CreateThread(NULL, NULL, ThreadProc, (LPVOID)client, NULL, NULL);

		printf("服务端%u连接上了服务器\n", client);
	}

	closesocket(server);

	return 0;
}


//线程处理函数
DWORD WINAPI ThreadProc(
	_In_ LPVOID param
)
{

	SOCKET client = (SOCKET)param;
	char buff[0x100] = { 0 };
	int recvSize;

	//保存客户端发送消息
	recv(client, buff, 0x100, 0);


	while ((recvSize = recv(client, buff, 0x100, 0)) > 0)
	{   

		//遍历vector,查看多少人连接服务器
		for (int i = 0; i < clientList.size();i++)
		{
			if (clientList[i] != client)
			{   //向非自身的客户端发送消息
				send(clientList[i], buff, recvSize, 0);
			}
		}
	}


	//跳出while循环,说明客户端离线,那就删除客户端节点
	for (int i = 0; i < clientList.size(); i++)
	{
		if (clientList[i] == client)
		{	
			
			printf("客户端%u断开连接\n", clientList[i]);
	
			closesocket(clientList[i]);	


			clientList.erase(clientList.begin() + i);

		
		}
	}


	return 0;
};

在这里面我们把客户端消息的处理放在了线程处理函数里面执行,由vector遍历已经连接的客户端,然后发送消息,达到消息同步的目的

客户端


#include<WinSock2.h>
//windows.h需要在winsock下面包含
#include<Windows.h>
//网络分为cs和bs'两种模式,cs是客户端和服务器交互,bs是游览器和服务器交互

#include<iostream>

#pragma comment(lib,"ws2_32.lib")

#include<WS2tcpip.h>

DWORD WINAPI reveMEssage(LPVOID param);

int main()
{
	//1.初始化网络环境
	//第一个参数 sock版本号
	//WSAStartup(0X0202);
	WSADATA date{ 0 };
	WSAStartup(MAKEWORD(2, 2), &date);

	//2 创建SOCKET
	//参数1 地址系列
	//参数二 套接类型
	//参数三 传输协议
	SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//3 绑定端口号和IP地址,让客户端可以链接
	//使用sockaddr_in结构体保存端口和ip
	sockaddr_in serverAddr{ 0 };

	serverAddr.sin_family = AF_INET;
	//绑定端口 需要用htons转换
	serverAddr.sin_port = htons(8888);

	//绑定ip地址
	inet_pton(AF_INET, "10.212.37.134", &serverAddr.sin_addr);

	int ret = connect(client, (SOCKADDR*)(&serverAddr), sizeof(serverAddr));

	if (ret != 0)
	{
		printf("连接服务器失败");
	}

	HANDLE hthread=CreateThread(0, 0, reveMEssage, (LPVOID)client, NULL, NULL);

	char buff[0x100]{ 0 };


	//持续读取客户端输入,如果输入exit则退出
	while (scanf_s("%s", buff, 0x100) && strcmp(buff, "exit"))
	{
		send(client, buff, strlen(buff) + 1,0);
	}

	closesocket(client);

	CloseHandle(hthread);

	return 0;

}


DWORD WINAPI reveMEssage(LPVOID param)
{
	SOCKET client = (SOCKET)param;
	char buff[0x100] = { 0 };
	int recvSize;




	while ((recvSize = recv(client, buff, 0x100, 0)) > 0)
	{
		printf("%s", buff);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值