1. windows 服务器端(select)
#include <iostream>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"Ws2_32.lib")
#include <map>
#include <thread>
#include <vector>
#include <mutex>
#include <set>
std::vector<SOCKET> fdVec;
std::mutex gol_mutex;
void LogPrint(const char* format, ...)
{
va_list args;
va_start(args, format);
char content[2048];
memset(content, 0, sizeof(content));
int ret = vsnprintf_s(content, 2048 - 1, format, args);
if (ret < 0)
{
return;
}
printf(content);
printf("\n");
va_end(args);
}
class NetThread
{
public:
NetThread()
{
FD_ZERO(&m_readSet);
maxSocket = 0;
}
~NetThread()
{
m_thread.join();
}
void SetThread(std::thread& t)
{
m_thread.swap(t);
}
void SetSockRead(SOCKET fd)
{
if (fd == -1)
{
return;
}
m_mutex.lock();
FD_SET(fd, &m_readSet);
if (fd > maxSocket)
{
maxSocket = fd;
}
m_mutex.unlock();
}
void run()
{
while (true)
{
timeval val;
val.tv_sec = 0;
val.tv_usec = 0;
m_mutex.lock();
fd_set tempReadSet = m_readSet;
m_mutex.unlock();
int ret = select(maxSocket + 1, &tempReadSet, NULL, NULL, &val);
if (ret == -1)
{
continue;
}
for (auto& socket : fdVec)
{
if (FD_ISSET(socket, &tempReadSet))
{
ReadData(socket);
}
}
//检测可删除列表,可用于心跳超时检测和发送失败检测
if (delSet.size() != 0)
{
for (auto iter = fdVec.begin(); iter != fdVec.end(); )
{
if (delSet.find(*iter) != delSet.end())
{
m_mutex.lock();
FD_CLR(*iter, &m_readSet);
m_mutex.unlock();
closesocket(*iter);
iter = fdVec.erase(iter);
continue;
}
++iter;
}
delSet.clear();
}
}
}
private:
void ReadData(SOCKET fd)
{
char buff[1024];
memset(buff, 0, sizeof(buff));
int ret = recv(fd, buff, sizeof(buff), 0);
if (ret != -1)
{
//接收缓冲为空,表示已断开连接
if (buff[0] == '\0')
{
LogPrint("fd(%d) 已断开连接...", fd);
delSet.insert(fd);
return;
}
LogPrint("fd = %d send MSG=%s", fd, buff);
gol_mutex.lock();
for (auto iter = fdVec.begin(); iter != fdVec.end(); ++iter)
{
ret = send(*iter, buff, sizeof(buff), 0);
if (ret == -1)
{
LogPrint("fd(%d) 已断开连接...", *iter);
delSet.insert(*iter);
}
}
gol_mutex.unlock();
}
}
private:
//可读列表
fd_set m_readSet;
//线程句柄
std::thread m_thread;
//线程锁
std::mutex m_mutex;
//最大描述符
SOCKET maxSocket;
//可删除的socket列表
std::set<SOCKET> delSet;
};
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
LogPrint("start up fail");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(10001);
SOCKET main_fd = socket(PF_INET, SOCK_STREAM, 0);
if (main_fd == -1)
{
LogPrint("create socket fail!");
return 1;
}
if (bind(main_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1)
{
LogPrint("bind fail!");
return 1;
}
listen(main_fd, 2);
NetThread netThread;
std::thread t(&NetThread::run, &netThread);
netThread.SetThread(t);
LogPrint("服务器已启动!");
while (true)
{
SOCKET new_sock = accept(main_fd, NULL, NULL);
if (new_sock != -1)
{
char buff[1024] = "服务器已连接成功!";
send(new_sock, buff, sizeof(buff), 0);
LogPrint("fd = %d 已连接服务器...", new_sock);
gol_mutex.lock();
fdVec.push_back(new_sock);
gol_mutex.unlock();
netThread.SetSockRead(new_sock);
}
}
WSACleanup();
}
2. 客户端
#include <iostream>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"Ws2_32.lib")
#include <thread>
void LogPrint(const char* format, ...)
{
va_list args;
va_start(args, format);
char content[2048];
memset(content, 0, sizeof(content));
int ret = vsnprintf_s(content, 2048 - 1, format, args);
if (ret < 0)
{
return;
}
printf(content);
printf("\n");
va_end(args);
}
void ReadData(SOCKET fd)
{
while (true)
{
char buff[1024];
memset(buff, 0, sizeof(buff));
int ret = recv(fd, buff, sizeof(buff), 0);
if (ret != -1)
{
LogPrint("fd=%d recv MSG=%s", fd, buff);
}
}
}
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
LogPrint("start up fail");
return 1;
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(10001);
SOCKET main_fd = socket(PF_INET, SOCK_STREAM, 0);
int ret = connect(main_fd, (const sockaddr*)&addr, sizeof(sockaddr_in));
if (ret == -1)
{
LogPrint("connect fail!");
return 1;
}
std::thread t(ReadData, main_fd);
//t.detach();
while (true)
{
char msg[1024];
memset(msg, 0, sizeof(msg));
scanf("%s", msg);
send(main_fd, msg, sizeof(msg), 0);
}
WSACleanup();
}
网友评论