服务端与客户端1.1——持续处理“单个客户端”发送的请求
上接程序1.0 socket基础api和服务端与客户端1.0_贪睡的蜗牛的博客-CSDN博客
1、 服务端做的修改
服务端原本为 (1)建立socket (2)绑定端口 (3) 监听端口 (4)等待客户端链接(5)向客户端发送一条数据(6)关闭socket 第四步和第五步处于循环状态 这里向客户端发送完一条数据就会继续的监听,如果有新的客户端来请求就会覆盖原先的连接
现在修改为:(1)建立socket (2)绑定端口 (3) 监听端口 (4)等待客户端链接(5)客户端发送的请求 (6)处理客户端发送的请求 (7)答复客户端的请求 (8)关闭socket 第五步到第七步处于循环状态
改造后将accept移出while循环,那么会持续的对这个连接接收发来的数据
2、客户端做的修改
客户端原先为 (1)建立socket (2)连接到服务端 (3)接收服务端发来的消息 (4)关闭socket 没有while循环,接收一次服务端发送来的请求就会关闭
客户端修改后为 (1)建立socket (2)连接到服务端 (3)发送请求 (4)得到请求结果 (5)关闭socket 3和4是持续的进行
代码
服务端修改后的代码
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<Windows.h>
#include<WinSock2.h>
#include<iostream>
#include<string>
using namespace std;
#pragma comment(lib,"ws2_32.lib") //windows socket2 32的lib库
int main()
{
//启动 windows socket 2.x 环境
WORD versionCode = MAKEWORD(2, 2); //创建一个版本号
WSADATA data;
WSAStartup(versionCode, &data); //启动Socket网络API的函数
///
//(1) 用Socket API建立简易的TCP服务端
// 1. 建立一个Socket
SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // ipv4 面向字节流的 tcp协议
// 2. 绑定接受客户端连接的端口 bind
sockaddr_in _sin = {};
_sin.sin_family = AF_INET;
_sin.sin_port = htons(4567); //端口号 host to net sockaddr_in中port是USHORT类型
//网络中port是 unsigend short类型 因此需要Htons进行转换
//_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //服务器绑定的IP地址 127.0.0.1是本地地址
_sin.sin_addr.S_un.S_addr = INADDR_ANY; //不限定访问该服务端的IP
if (bind(_sock, (sockaddr*)&_sin, sizeof(_sin)) == SOCKET_ERROR) //sockaddr 不利于编码
{
cout << "ERROR: 绑定用于接受客户端连接的网络端口失败..." << endl;
}
else
{
cout << "SUCCESS: 绑定端口成功..." << endl;
}
// 3. 监听网络端口 listen
if (listen(_sock, 5) == SOCKET_ERROR)//第二个参数 backbag 最大允许连接数量
{
cout << "ERROR: 监听用于接受客户端连接的网络端口失败..." << endl;
}
else
{
cout << "SUCCESS: 监听端口成功..." << endl;
}
// 4. 等待接受客户端连接 accept
sockaddr_in _clientAddr = {};
int cliendAddrLen = sizeof(_clientAddr);
SOCKET _clientSock = INVALID_SOCKET; // 初始化无效的socket 用来存储接入的客户端
_clientSock = accept(_sock, (sockaddr*)&_clientAddr, &cliendAddrLen);
while (true)
{
char _recvBuf[128] = {};
int nlen = recv(_clientSock, _recvBuf, 128, 0); //接受客户端的数据 第一个参数应该是客户端的socket对象
if (nlen <= 0)
{
//客户端退出
cout << "客户端已退出,任务结束" << endl;
break;
}
cout << "收到命令:" << _recvBuf << endl;
//6 处理请求 这里只是简单的字符串判断
if (0 == strcmp(_recvBuf, "getName"))
{
// 7. 向客户端发送一条数据 send
char msgBuf[] = "Evila";
send(_clientSock, msgBuf, strlen(msgBuf) + 1, 0); //+1是为了把\0算进去
}
else if (0 == strcmp(_recvBuf, "getAge"))
{
// 7. 向客户端发送一条数据 send
char msgBuf[] = "80";
send(_clientSock, msgBuf, strlen(msgBuf) + 1, 0); //+1是为了把\0算进去
}
else
{
// 7. 向客户端发送一条数据 send
char msgBuf[] = "Hello, I'm Server";
send(_clientSock, msgBuf, strlen(msgBuf) + 1, 0); //+1是为了把\0算进去
}
}
// 6. 关闭socket
closesocket(_sock);
// 清除Windows socket环境
WSACleanup();
return 0;
}
客户端修改后的代码
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<Windows.h>
#include<WinSock2.h>
#include<iostream>
#include<string>
using namespace std;
#pragma comment(lib,"ws2_32.lib") //windows socket2 32的lib库
int main()
{
//启动 windows socket 2.x 环境
WORD versionCode = MAKEWORD(2, 2); //创建一个版本号
WSADATA data;
WSAStartup(versionCode, &data); //启动Socket网络API的函数
///
//(1) 用Socket API建立简易的TCP客户端
// 1. 建立一个Socket 下面第三个参数不需要指定
SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0); // ipv4 面向字节流的 tcp协议
if (INVALID_SOCKET == _sock)
{
cout << "错误,建立socket失败"<<endl;
}
else
{
cout << "成功建立客户端socket"<<endl;
}
// 2. 连接服务器 connect
sockaddr_in _sin = {};
_sin.sin_family = AF_INET;
_sin.sin_port = htons(4567); //端口号 host to net sockaddr_in中port是USHORT类型
//网络中port是 unsigend short类型 因此需要Htons进行转换
//_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //服务器绑定的IP地址 127.0.0.1是本地地址
_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int ret = connect(_sock, (sockaddr*)&_sin, sizeof(sockaddr_in));
if (SOCKET_ERROR == ret)
{
cout << "错误,connect失败" << endl;
}
else
{
cout << "成功,connect 成功" << endl;
}
//3 接收服务器数据 resv
char recvBuf[256] = {};
while (true)
{
// 获取请求命令
char cmdBuf[128] = {};
cout << "输入命令: ";
cin >> cmdBuf;
// 4 处理请求
if (strcmp(cmdBuf, "exit") == 0)
{
break;
}
else
{
// 5 向服务器发送请求命令
send(_sock, cmdBuf, strlen(cmdBuf) + 1, 0);
}
//放到循环中 重复接受服务器的返回信息
//6. 接受服务器信息 recv
char recvBuf[256] = {};
int nlen = recv(_sock, recvBuf, sizeof(recvBuf), 0); //返回值是接收数据的长度
if (nlen > 0)
{
cout << recvBuf << endl;
}
else
{
cout << "ERROR: 数据传输失败..." << endl;
}
}
// 6. 关闭socket
closesocket(_sock);
// 清除Windows socket环境
WSACleanup();
getchar();//防止一闪而过
return 0;
}
总结
- 客户端在连接服务端后形成后的socket就是与服务端沟通的桥梁,通过这个socket不断地与服务端send和recv即可实现与服务端的通信
- 服务端与客户端之间也是通过socket实现提供服务
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战