原理解释参考:https://www.jianshu.com/p/066d99da7cbd
服务器;
#include <iostream>
#include<iostream>
#include<string>
#include<cstring>
#include<WS2tcpip.h>//处理ip与port的相关方法
//#include <WinSock2.h> //一般情况下,这个头文件位于windows.h之前,避免发生某些错误
#include<Windows.h>
#include <thread>
#include "IOCPServer.h"
#pragma comment(lib,"ws2_32.lib")
using namespace std;
//the following are UBUNTU/LINUX ONLY terminal color codes.
#define RESET "\033[0m"
#define BLACK "\033[30m" /* Black */
#define RED "\033[31m" /* Red */
#define GREEN "\033[32m" /* Green */
#define YELLOW "\033[33m" /* Yellow */
#define BLUE "\033[34m" /* Blue */
#define MAGENTA "\033[35m" /* Magenta */
#define CYAN "\033[36m" /* Cyan */
#define WHITE "\033[37m" /* White */
#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */
#define BOLDRED "\033[1m\033[31m" /* Bold Red */
#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */
#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */
#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */
#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */
#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */
#define BOLDWHITE "\033[1m\033[37m" /* Bold White */
void clientThread(SOCKET recvClientSocket)
{
while (true) {
if(errno == EINTR)
{
cout << "客户端已经断开,等待新的连接EINTR"<< endl;
}
char recvBuf[1024] = {};
int reLen = recv(recvClientSocket, recvBuf, 1024, 0); //阻塞函数,等待接收数据
if (SOCKET_ERROR == reLen) {//客户端断开
cout << "客户端["<< recvClientSocket <<"]已经断开"<< endl;
break;//退出线程
}
cout << RED<< "客户端["<< recvClientSocket <<"]请求命令:" << recvBuf << endl;
if (0 == strcmp("cls", recvBuf)) {
system(recvBuf);//服务端执行命令 ,清空服务器窗口命令
}
else if (0 == strcmp("获取版本信息", recvBuf)) {
string verData = "Version: 1.0.1\nAuthor: Primer\nReleaseData: 2019-04-21";//返回数据
int sLen = send(recvClientSocket, const_cast<char *>(verData.c_str()), verData.length(), 0);
}
else if (0 == strcmp("exit", recvBuf)) {
string verData = "Client request to exit.";//返回数据
int sLen = send(recvClientSocket, const_cast<char *>(verData.c_str()), verData.length(), 0);
cout << endl << "退出服务器" << endl;
break;
}
else
{
string verData = "收到了";//返回数据
int sLen = send(recvClientSocket, const_cast<char *>(verData.c_str()), verData.length(), 0);
}
cout << endl;
}
closesocket(recvClientSocket);
}
int main()
{
//cout << "-----------服务器-----------" << endl;
//初始化socket库,否则会创建套接字失败
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 0);
if (0 != WSAStartup(sockVersion, &wsaData))
{
cout << "Failed to retrive socket version."<< endl;
return -1;
}
//1.创建服务器的套接字
SOCKET serviceSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SOCKET_ERROR == serviceSocket)
{
cout << "套接字创建失败!" << endl;
return -1;
}
else
{
cout << "套接字创建成功!" << endl;
}
// 3 绑定套接字 指定绑定的IP地址和端口号
sockaddr_in socketAddr{}; //一个绑定地址:有IP地址,有端口号,有协议族
socketAddr.sin_family = AF_INET; // 使用ipv4
//socketAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //127.开头的都是本地
//inet_addr()函数用起来会出现错误所以需要简单修改一下设置:项目>属性>配置属性>C/C++>所有选项>SDL检查设置为否可通过编译。
inet_pton(AF_INET, "127.0.0.1", &socketAddr.sin_addr);//功能同上,绑定ip,新版转换函数,为了适应ipv6
socketAddr.sin_port = htons(8000); //端口号用函数转变类型
int bRes = bind(serviceSocket, reinterpret_cast<SOCKADDR*>(&socketAddr), sizeof(SOCKADDR));
if (SOCKET_ERROR == bRes) {cout << "绑定失败!" << endl;return -1;}
else {cout << "绑定成功!" << endl;}
// 4 服务器监听
int lLen = listen(serviceSocket, 5); //监听的第二个参数就是:能存放多少个客户端请求,到并发编程的时候很有用
if (SOCKET_ERROR == lLen) {cout << "监听失败!" << endl; return -1;}
else {cout << "监听成功!" << endl;}
while(true)
{
// 5 接受请求
sockaddr_in revClientAddr{};
int _revSize = sizeof(sockaddr_in);
auto recvClientSocket = accept(serviceSocket, reinterpret_cast<SOCKADDR *>(&revClientAddr), &_revSize);
if (INVALID_SOCKET != recvClientSocket)
{
cout << "服务端[" << std::to_string(serviceSocket) << "]接受客户端[" << std::to_string(recvClientSocket) << "]请求成功!" << endl;
std::thread client(clientThread, recvClientSocket);
client.detach();
}
}
closesocket(serviceSocket);
// 8 终止
WSACleanup();
cout << "服务器停止" << endl;
return 0;
}
客户端:
#include <iostream>
#include<iostream>
#include<string>
#include<cstring>
#include<WS2tcpip.h>
#include <WinSock2.h> //一般情况下,这个头文件位于windows.h之前,避免发生某些错误
#include<Windows.h>
#pragma comment(lib,"ws2_32.lib")
//the following are UBUNTU/LINUX ONLY terminal color codes.
#define RESET "\033[0m"
#define BLACK "\033[30m" /* Black */
#define RED "\033[31m" /* Red */
#define GREEN "\033[32m" /* Green */
#define YELLOW "\033[33m" /* Yellow */
#define BLUE "\033[34m" /* Blue */
#define MAGENTA "\033[35m" /* Magenta */
#define CYAN "\033[36m" /* Cyan */
#define WHITE "\033[37m" /* White */
#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */
#define BOLDRED "\033[1m\033[31m" /* Bold Red */
#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */
#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */
#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */
#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */
#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */
#define BOLDWHITE "\033[1m\033[37m" /* Bold White */
using namespace std;
int main()
{
cout << "-----------客户端-----------" << endl;
//初始化socket库,否则会创建套接字失败
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 0);
if (0 != WSAStartup(sockVersion, &wsaData))
{
cout << "Failed to retrive socket version."<< endl;
return -1;
}
//1.创建套接字
SOCKET clientSocket = socket(PF_INET, SOCK_STREAM, 0);
if (SOCKET_ERROR == clientSocket) { cout << "套接字闯创建失败!" << endl; }
else { cout << "套接字创建成功!" << endl; }
//将socket设置为非阻塞模式,send/recv将不会阻塞
unsigned long ul=1;
int ret = ioctlsocket(clientSocket, FIONBIO, (unsigned long *)&ul);//设置成非阻塞模式。
if(ret==SOCKET_ERROR) //设置失败
{
cout << "套接字设置非阻塞失败!" << endl;
return -1;
}
//2. 绑定套接字 指定服务器的IP地址和端口号
sockaddr_in socketAddr{};
socketAddr.sin_family = PF_INET;
inet_pton(AF_INET, "127.0.0.1", &socketAddr.sin_addr);
socketAddr.sin_port = htons(1234);
//3.连接服务器
int cRes = connect(clientSocket, reinterpret_cast<SOCKADDR*>(&socketAddr), sizeof(SOCKADDR));//连接成功返回0
if (SOCKET_ERROR == cRes) { cout << "客户端:\t\t与服务器连接失败....." << endl; }
else { cout << "客户端["<< std::to_string(clientSocket)<<"]与服务器[ 127.0.0.1]连接成功" << endl; }
while (true) {
string s;
cout <<GREEN<< "请输入发送数据:";
getline(cin, s); //可输入空格,默认以换行符结束输入,
//4. 发送数据
send(clientSocket, const_cast<char*>(s.c_str()), s.length(), 0);
//5.接受 数据
char recvBuf[4024] = {};
int reLen = recv(clientSocket, recvBuf, 4024, 0);//阻塞函数,等待接受数据
cout << RED << "接收的消息: "<<recvBuf << endl;
if (0 == strcmp("exit", s.c_str())) {
break;
}
}
//6.关闭socket
closesocket(clientSocket);
//终止
WSACleanup();
cout << "客户端退出" << endl;
return 0;
}