介绍
C++ Windows实现EchoServer非阻塞客户端(TPC协议)
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; }
文章有(1)条网友点评
这个代码有问题,在读取的时候容易出错,就当作参考吧