IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 五、Socket网络通信基础(二):结构化的网络消息数据收发 -> 正文阅读

[网络协议]五、Socket网络通信基础(二):结构化的网络消息数据收发

前言

在上一篇中Socket网络通信基础(一):简易TCP服务端和客户端
server使用while循环来持续accept新的client连接
但是client连接上server后,在recv接收到server消息后,就退出了

本篇优化方向
1、让client可以发送自定义的消息,并在收到server消息后继续循环等待新的指令
2、server和client使用结构化的网络消息数据交互

一、优化内容

1、新增结构化消息DataPackage

struct DataPackage
{
	int age;
	char name[32];
};

2、server的while优化

根据收到的client命令向client发送不同的消息

while (true)
	{
		int nLen = recv(sock_client, recvBuf, 128, 0);
		if (nLen <= 0)
		{
			printf("客户端已退出,任务结束。\n");
			break;
		}
		printf("收到命令:%s \n", recvBuf);
		if (0 == strcmp(recvBuf, "getInfo"))
		{
			DataPackage dp = { 80,"张三" };
			send(sock_client, (const char*)&dp, sizeof(DataPackage), 0);
		}
		else
		{
			char msgBuf[] = "???.";
			send(sock_client, msgBuf, strlen(msgBuf) + 1, 0);
		}
	}

3、client持续send逻辑

  • 使用scanf来接收用户的命令输入
  • 根据用户输入的指令分别执行退出、发送消息
  • 根据server返回的消息内容转换成DataPackage结构体指针并打印输出
	while (true)
	{
		char cmdBuf[128] = {};
		scanf("%s", cmdBuf);
		if (0 == strcmp(cmdBuf, "exit"))
		{
			printf("收到exit命令,任务结束。\n");
			break;
		}
		else
		{
			send(sock_client, cmdBuf, strlen(cmdBuf) + 1, 0);
		}
		char recvBuf[128] = {};
		int nLen = recv(sock_client, recvBuf, 128, 0);
		if (nLen > 0)
		{
			DataPackage* dp = (DataPackage*)recvBuf;
			printf("接收到数据:年龄=%d,姓名=%s \n", dp->age, dp->name);
		}
	}

二、测试结果

  • 这里我们还发现个问题
    当消息内容getInfo正确的时候,是可以正常解析的
    但是当内容错误的话,client依然会收到server返回的消息
    这时候再解析成DataPackage就出问题
    这个后续我们再解决
    在这里插入图片描述
    在这里插入图片描述

三、server是如何知道client退出的

首先TCP协议的连接是经过三次握手,断开是经过四次握手(更具体大家可以查资料)
我们可以在client的closesocket处断点,然后在client中输入命令exit
这时候可以看到当client的closesocket执行后,server就已经收到recv的nLen=0
客户端退出

在这里插入图片描述

四、完整源码

1、server.cpp

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS

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

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

struct DataPackage
{
	int age;
	char name[32];
};

int main()
{
	WORD ver = MAKEWORD(2, 2);
	WSADATA dat;
	WSAStartup(ver, &dat);

	SOCKET sock_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sock_server)
	{
		printf("socket 创建失败\n");
		WSACleanup();
		return -1;
	}

	sockaddr_in _sin = {};
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);
	_sin.sin_addr.S_un.S_addr = INADDR_ANY;// INADDR_ANY:这个代表本机的地址都可以访问,如IPV4,IPV6
	//_sin.sin_addr.s_addr = inet_addr("127.0.0.1");// 指定地址的绑定

	if (SOCKET_ERROR == bind(sock_server, (sockaddr*)&_sin, sizeof(_sin)))
	{
		printf("ERROR,绑定网络端口失败...\n");
		closesocket(sock_server);
		WSACleanup();
		return -1;
	}
	else
	{
		printf("绑定网络端口成功...\n");
	}
	if (SOCKET_ERROR == listen(sock_server, 5))
	{
		printf("ERROR,监听网络端口失败...\n");
		closesocket(sock_server);
		WSACleanup();
		return -1;
	}
	else
	{
		printf("监听网络端口成功...\n");
	}

	sockaddr_in clientAddr = {};
	int nAddrLen = sizeof(clientAddr);
	SOCKET sock_client = INVALID_SOCKET;

	sock_client = accept(sock_server, (sockaddr*)&clientAddr, &nAddrLen);
	if (INVALID_SOCKET == sock_client)
	{
		printf("错误,接受到无效客户端SOCKET...\n");
		closesocket(sock_server);
		WSACleanup();
		return -1;
	}
	printf("新客户端加入:IP = %s \n", inet_ntoa(clientAddr.sin_addr));

	char recvBuf[128] = {};
	while (true)
	{
		int nLen = recv(sock_client, recvBuf, 128, 0);
		if (nLen <= 0)
		{
			printf("<nLen=%d>,客户端已退出,任务结束。\n", nLen);
			break;
		}
		printf("收到命令:%s \n", recvBuf);

		if (0 == strcmp(recvBuf, "getInfo"))
		{
			DataPackage dp = { 80,"张三" };
			send(sock_client, (const char*)&dp, sizeof(DataPackage), 0);
		}
		else
		{
			char msgBuf[] = "???.";
			send(sock_client, msgBuf, strlen(msgBuf) + 1, 0);
		}
	}

	closesocket(sock_server);
	WSACleanup();
	printf("已退出,任务结束。\n");
	getchar();
	return 0;
}

2、client.cpp

#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS

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

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

struct DataPackage
{
	int age;
	char name[32];
};

int main()
{
	WORD ver = MAKEWORD(2, 2);
	WSADATA dat;
	WSAStartup(ver, &dat);

	SOCKET sock_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sock_client)
	{
		printf("socket 创建失败\n");
		WSACleanup();
		return -1;
	}

	sockaddr_in _sin = {};
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);
	_sin.sin_addr.s_addr = inet_addr("127.0.0.1");

	int ret = connect(sock_client, (sockaddr*)&_sin, sizeof(_sin));
	if (SOCKET_ERROR == ret)
	{
		printf("错误,连接服务器失败...\n");
		closesocket(sock_client);
		WSACleanup();
		return -1;
	}
	else
	{
		printf("连接服务器成功...\n");
	}

	while (true)
	{
		char cmdBuf[128] = {};
		scanf("%s", cmdBuf);
		if (0 == strcmp(cmdBuf, "exit"))
		{
			printf("收到exit命令,任务结束。\n");
			break;
		}
		else
		{
			send(sock_client, cmdBuf, strlen(cmdBuf) + 1, 0);
		}
		char recvBuf[128] = {};
		int nLen = recv(sock_client, recvBuf, 128, 0);
		if (nLen > 0)
		{
			DataPackage* dp = (DataPackage*)recvBuf;
			printf("接收到数据:年龄=%d,姓名=%s \n", dp->age, dp->name);
		}
	}

	closesocket(sock_client);
	WSACleanup();
	printf("已退出,任务结束。\n");
	getchar();
	return 0;
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-01-08 14:25:09  更:2022-01-08 14:25:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年10日历 -2024/10/5 9:21:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码