介绍
C++ Windows实现EchoServer非阻塞客户端(TPC协议)
服务端文章在:http://t.csdnimg.cn/tCpOD
Windows IDE:Visual Studio 2022
我们将采用分文件编写方式
支持库
#include <string>
#include <winsock2.h>
代码
main.h
#pragma once
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <string>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
class EchoClient
{
private:
SOCKET socketFD = 0;
WORD sockVersion;
WSADATA data;
int InitCode;
timeval timeout{};
sockaddr_in serAddr{};
fd_set wait{};
int bufferSize = 1024;
bool block;
public:
EchoClient();
~EchoClient();
int connectServer(std::string ip, int port, bool noBlock = true);
int sendServerDate(std::string date);
void closeConnect();
void setTimeout(int s = 3, int us = 0);
std::string getServerDate();
};
main.cpp
#include "main.h"
EchoClient::EchoClient()
{
sockVersion = MAKEWORD(2, 2);
InitCode = WSAStartup(sockVersion, &data);
setTimeout();
}
EchoClient::~EchoClient()
{
WSACleanup();
}
int EchoClient::connectServer(std::string ip, int port, bool noBlock) {
if (InitCode != 0)
return -3;
socketFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketFD == INVALID_SOCKET)
return -2;
if (noBlock) {
u_long on = 1;
if (ioctlsocket(socketFD, FIONBIO, &on) < 0) {
return -4;
}
}
block = !noBlock;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(port);
serAddr.sin_addr.S_un.S_addr = inet_addr(ip.c_str());
int ret = connect(socketFD, (sockaddr*)&serAddr, sizeof(serAddr));
if (block) {
if (ret >= 0)
return 0;
else
return -1;
}
if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
return -2;
}
FD_ZERO(&wait);
FD_SET(socketFD, &wait);
timeval tv = timeout;
ret = select(socketFD + 1, NULL, &wait, NULL, &tv);
if (ret == 0) {
return -1;
}
else if (ret < 0) {
return -2;
}
return 0;
}
int EchoClient::sendServerDate(std::string date)
{
int code = send(socketFD, date.c_str(), date.size(), 0);
return code;
}
void EchoClient::closeConnect()
{
closesocket(socketFD);
}
void EchoClient::setTimeout(int s, int us)
{
timeout.tv_sec = s;
timeout.tv_usec = us;
}
std::string EchoClient::getServerDate()
{
std::string result = "";
char * buffer = new char[bufferSize];
int len = 0,ready;
buffer[len] = '\0';
timeval tv = timeout;
FD_ZERO(&wait);
FD_SET(socketFD, &wait);
while (true)
{
if (block)
goto getMessage;
ready = select(socketFD + 1, &wait, NULL, NULL, &tv);
if (ready > 0) {
if (FD_ISSET(socketFD, &wait)) {
getMessage:
len = recv(socketFD, buffer, bufferSize - 1, 0);
if (len > 0) {
buffer[len] = '\0';
result.append(buffer);
if (block)
continue;
}
else
break;
}
}
else
break;
}
delete[] buffer;
return result;
}
示例
假设服务端地址:192.168.2.2 | 端口是1001
#include "main.h"
#include <iostream>
int main()
{
std::string ip = "192.168.2.2";
EchoClient ehoClient;
while (true)
{
std::cout << "开始连接:" << ip;
if (ehoClient.connectServer(ip, 1001) == 0) {
ehoClient.setTimeout(1);
ehoClient.sendServerDate("hello");
std::string result = ehoClient.getServerDate();
std::cout << "[Success] 发送数据:hello | 返回数据:" << result << "\n";
if (result == "close") {
std::cout << "Find:" << ip;
ehoClient.closeConnect();
break;
}
}
else {
std::cout << "[Fail]\n";
}
}
return 0;
}
这里展示一下局域网快速搜索
假设局域网IP段是192.168.222 | 端口是1001
#include "main.h"
#include <iostream>
int main()
{
std::string ipBasic = "192.168.222.";
std::string ip = "";
uint8_t i = 0;
EchoClient ehoClient;
ehoClient.setTimeout(0,1000);
while (true)
{
ip = ipBasic + std::to_string(i++);
std::cout << "开始连接:" << ip;
if (ehoClient.connectServer(ip, 1001) == 0) {
ehoClient.setTimeout(1);
ehoClient.sendServerDate("hello");
std::string result = ehoClient.getServerDate();
std::cout << "[Success] 发送数据:hello | 返回数据:" << result << "\n";
if (result == "close") {
std::cout << "Find:" << ip;
ehoClient.closeConnect();
break;
}
}
else {
std::cout << "[Fail]\n";
}
}
return 0;
}