2-4 建立能持续处理请求的CS程序

2-4 建立能持续处理请求的C/S程序

0-前言

【C++百万并发网络通信】系列是跟着【张远东】老师的视频来复现的

希望能通过博客的方式不断坚持学习,也希望偶然间看到这篇博客的你也能一起加油!

笔记目录:【C++百万并发网络通信-笔记目录】

1-步骤说明

在这里插入图片描述

相较于【简易的TCP C/S结构】,【1.1】版本将要实现Server循环接收客户端请求(recv)并且处理请求(strcmp)

2-服务端1.1

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include<Windows.h>
#include<WinSock2.h>
#include<iostream>

using namespace std;

#pragma comment(lib, "ws2_32.lib")//加入静态链接库

int main()
{
    
    
	WORD ver = MAKEWORD(2, 2);//WORD版本号
	WSADATA dat;//一种数据结构
	//启动windows socket 2.x环境
	WSAStartup(ver, &dat);
	//-------------------

	//--建立简易TCP服务端
	// 1 建立socket
	SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	// 2 绑定端口 bind
	sockaddr_in _sin = {
    
    };//网络端口地址
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);//host to net unsigned short,服务器使用该端口进行监听
	_sin.sin_addr.S_un.S_addr = INADDR_ANY;//随意ip地址//inet_addr("127.0.0.1");//本机地址,防止外网访问
	if (SOCKET_ERROR == bind(_sock, (sockaddr*)&_sin, sizeof(_sin)))
	{
    
    
		cout << "Error:绑定用于接收客户端连接的网络端口失败" << endl;
	}
	else
	{
    
    
		cout << "Success:绑定网络端口成功..." << endl;
	}

	// 3 监听端口 listen
	if (SOCKET_ERROR == listen(_sock, 5))
	{
    
    
		cout << "Error:监听网络端口失败" << endl;
	}
	else
	{
    
    
		cout << "Success:监听网络端口成功..." << endl;
	}

	// 4 等待客户端连接 accept
	sockaddr_in clientAddr = {
    
    };//远程客户端地址
	int nAddrLen = sizeof(clientAddr);//结构长度
	SOCKET _csock = INVALID_SOCKET;//无效的socket地址

	_csock = accept(_sock, (sockaddr*)&clientAddr, &nAddrLen);//新加入的客户端socket
	if (INVALID_SOCKET == _csock)
	{
    
    
		cout << "Error:接收到无效客户端socket..." << endl;
	}
	cout << "新客户端加入:socket = " << (int)_csock << " , IP = " << inet_ntoa(clientAddr.sin_addr) << endl;

	while (true)
	{
    
    
		//5 接收客户端数据
		char _recvBuf[128] = {
    
    };
		int nLen = recv(_csock, _recvBuf, 128, 0);//返回客户端发送的数据长度
		if (nLen <= 0)
		{
    
    
			cout << "客户端已退出,任务结束!" << endl;
			break;
		}
		cout << "收到命令: " << _recvBuf << endl;
		//6 处理客户端请求,按照请求向客户端发送数据
		if (0 == strcmp(_recvBuf, "getName"))
		{
    
    
			char msgBuf[] = "Xiao Qiang";
			send(_csock, msgBuf, strlen(msgBuf) + 1, 0);
		}
		else if (0 == strcmp(_recvBuf, "getAge"))
		{
    
    
			char msgBuf[] = "20";
			send(_csock, msgBuf, strlen(msgBuf) + 1, 0);
		}
		else
		{
    
    
			char msgBuf[] = "???";
			send(_csock, msgBuf, strlen(msgBuf) + 1, 0);
		}
	}

	// 7 关闭socket closesocket
	closesocket(_sock);
	//-------------------
	//清除Windows socket环境
	WSACleanup();//关闭windows socket网络环境
	cout << "已退出,任务结束..." << endl;
	system("pause");
	return 0;
}

这里相比于上一个版本【简易的TCP C/S结构】,将【等待客户端连接】移除while循环,因此造成服务端只能接入一台客户端,并且这台客户端退出后,服务端不能再接受新的客户端

【循环接收客户端信息】:

在while循环中,加入recv()函数来接收客户端发送的数据,注意当客户端退出时,还会向服务端发送一条数据,此时就是nLen<=0的情况。

【循环处理客户端请求】:

将客户端发送的数据与已有的命令getNamegetAge通过strcmp函数进行对比,对比成功的请求会返回相应的数据

strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。

3-客户端1.1

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include<Windows.h>
#include<WinSock2.h>
#include<iostream>

using namespace std;
#pragma comment(lib, "ws2_32.lib")//加入静态链接库

int main()
{
    
    
	WORD ver = MAKEWORD(2, 2);//WORD版本号
	WSADATA dat;//一种数据结构
	//启动windows socket 2.x环境
	WSAStartup(ver, &dat);
	//-------------------
	//--建立简易TCP客户端
	// 1 建立socket
	SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0);//0:不规定协议类型
	if (INVALID_SOCKET == _sock)
		cout << "Error:建立Socket失败!" << endl;
	else
		cout << "建立Socket成功..." << endl;

	// 2 连接服务器 connect
	sockaddr_in _sin = {
    
    }; //能够将结构体快速初始化
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);//客户端想要连接服务器的哪个端口
	_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//连接服务器的ip地址,127.0.0.1是本机地址
	int res = connect(_sock, (sockaddr*)&_sin, sizeof(sockaddr_in));
	if (SOCKET_ERROR == res)
		cout << "Error:连接失败!" << endl;
	else
		cout << "连接成功..." << endl;

	while (true)
	{
    
    
		//3 输入请求命令
		char cmdBuf[128] = {
    
    };
		cin >> cmdBuf;
		//4 处理请求
		if (0 == strcmp(cmdBuf, "exit"))
		{
    
    
			cout << "收到exit命令,任务结束..." << endl;
			break;
		}

		//5 向服务器发送请求
		send(_sock, cmdBuf, strlen(cmdBuf) + 1, 0);

		// 6 接收服务器信息 recv
		char recvBuf[128] = {
    
    };//接收数据缓冲区
		int nLen = recv(_sock, recvBuf, 128, 0);//recv()返回接收数据的长度
		if (nLen > 0)
			cout << "接收到数据:" << recvBuf << endl;
	}

	// 7 关闭socket closesocket
	closesocket(_sock);
	//-------------------
	//清除Windows socket环境
	WSACleanup();//关闭windows socket网络环境
	cout << "已退出。" << endl;
	system("pause");
	return 0;
}

【循环输入请求】

由用户输入命令到cmdBuf字符串中,exit命令可以直接退出客户端

【循环发送请求】

cmdBuf中的命令发送给客户端套接字_csock

4-运行结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44484715/article/details/112441611
2-4