小结
之前写过一个服务器,后来发现那个只能在窗口模式下运行,不然没有窗口句柄,怎么才能获取窗口消息呢,想想也是,又写了一个在控制台下的运行类吧。
继续造
- **WSAStartup ** ,windows异步套接字的启动;还是老套路
DWORD dwCode;
WSADATA wsaData;
dwCode = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (dwCode != 0)
{
MessageBox(NULL, L"Can't find find a usable WinSock DLL", L"Error", 0);
return;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
MessageBox(NULL, L"Can't find the socket version required.", L"Error", 0);
return;
}
- 创建socket,绑定socket端口和IP,创建线程,注意这里用的是C++11,用的线程比较方便
m_sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_sServer == INVALID_SOCKET)
{
std::cout << "Can't create the socket, error code" << WSAGetLastError() << std::endl;
return FALSE;
}
SOCKADDR_IN sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);//ADDR_ANY;
//sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sockAddr.sin_port = htons(port);
int dwCode = ::bind(m_sServer, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
if (dwCode == SOCKET_ERROR)
{
closesocket(m_sServer);
std::cout << "Can't bind the socket, error code:" << WSAGetLastError() << std::endl;
return FALSE;
}
if (listen(m_sServer, maxlink) == SOCKET_ERROR)
{
std::cout << "Can't listen the socket, error code:" << WSAGetLastError() << std::endl;
return FALSE;
}
m_hAccepthEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
thread _threadRecv(ThreadRecv, this);
_threadRecv.detach();
- 管理socket,接受消息;
fd_set server_fd_set; // 管理所有 socket 的集合
timeval tv;
FD_ZERO(&server_fd_set);
FD_SET(m_sServer, &server_fd_set); // 将监听 socket 添加到集合里
tv.tv_sec = 0;
tv.tv_usec = 0;
int ret = select(0, &server_fd_set, NULL, NULL, &tv); // 等待监听集合里所有的句柄
if (ret < 0) {
printf("Select error\n");
}
// 监听端口进来的连接信息
if (FD_ISSET(m_sServer, &server_fd_set)) { // 监听端口有可读数据
// 将端口监听进来
//struct sockaddr_in c_addr;
//int len = sizeof(c_addr);
//SOCKET client_socket = accept(m_sServer, (struct sockaddr*)&c_addr, &len);
SOCKADDR_IN addrServer = { 0 };
int iaddrLen = sizeof(addrServer);
SOCKET client_socket = accept(m_sServer, (SOCKADDR*)&addrServer, &iaddrLen);
if (client_socket != INVALID_SOCKET) {
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addrServer.sin_addr, str, sizeof(str));
TcpClient _tcp(client_socket, str, true);
m_TcpClient.push_back(_tcp);
printf("accept a connection from IP: %s,Port: %d\n", str, htons(addrServer.sin_port));
}
}
- 直接上代码,TcpServer头文件;
#pragma once
#include <string>
#include <map>
#include <vector>
#include <thread>
#include <mutex>
#include <WS2tcpip.h>
using namespace std;
#include <WinSock2.h>
#pragma comment( lib, "ws2_32.lib" )
struct TcpClient
{
SOCKET socket; // SOCKET
char addr[INET_ADDRSTRLEN]; // 地址
bool bConnect; // 是否连接
TcpClient() {
socket = INVALID_SOCKET;
bConnect = false;
ZeroMemory(addr, sizeof(addr));
}
TcpClient(SOCKET s, char* _addr, bool c) {
socket = s;
strcpy_s(addr, _addr);
bConnect = c;
}
};
class TcpServer
{
public:
TcpServer();
~TcpServer();
BOOL InitSocket(int port, int maxlink = 255);
static void ThreadRecv(TcpServer* pThis);
void ESThreadRecv();
void send_msg(PVOID pM);
void send_msg(PVOID pM, int len);
private:
SOCKET m_sServer;
HANDLE m_hAccepthEvent;
vector<TcpClient> m_TcpClient;
mutex m_mtx;
};
- 继续上代码,TcpServer源文件;
#include "TcpServer.h"
#include <iostream>
TcpServer::TcpServer() :
m_sServer(INVALID_SOCKET),
m_hAccepthEvent(INVALID_HANDLE_VALUE)
{
DWORD dwCode;
WSADATA wsaData;
dwCode = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (dwCode != 0)
{
MessageBox(NULL, L"Can't find find a usable WinSock DLL", L"Error", 0);
return;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
MessageBox(NULL, L"Can't find the socket version required.", L"Error", 0);
return;
}
}
TcpServer::~TcpServer()
{
CloseHandle(m_hAccepthEvent);
m_hAccepthEvent = INVALID_HANDLE_VALUE;
Sleep(1000);
//关闭socket
::closesocket(m_sServer);
for (int i = 0; i < m_TcpClient.size(); i++)
{
::closesocket(m_TcpClient[i].socket);
}
m_TcpClient.clear();
WSACleanup();
}
BOOL TcpServer::InitSocket(int port,int maxlink)
{
m_sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_sServer == INVALID_SOCKET)
{
std::cout << "Can't create the socket, error code" << WSAGetLastError() << std::endl;
return FALSE;
}
SOCKADDR_IN sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);//ADDR_ANY;
//sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sockAddr.sin_port = htons(port);
int dwCode = ::bind(m_sServer, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
if (dwCode == SOCKET_ERROR)
{
closesocket(m_sServer);
std::cout << "Can't bind the socket, error code:" << WSAGetLastError() << std::endl;
return FALSE;
}
if (listen(m_sServer, maxlink) == SOCKET_ERROR)
{
std::cout << "Can't listen the socket, error code:" << WSAGetLastError() << std::endl;
return FALSE;
}
m_hAccepthEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
thread _threadRecv(ThreadRecv, this);
_threadRecv.detach();
return TRUE;
}
void TcpServer::ThreadRecv(TcpServer* pThis)
{
pThis->ESThreadRecv();
}
void TcpServer::ESThreadRecv()
{
fd_set server_fd_set; // 管理所有 socket 的集合
timeval tv;
int retRead;
char pBuffer[2048];
while (true)
{
DWORD dwCode = WaitForSingleObject(m_hAccepthEvent, INFINITE);
if (dwCode != WAIT_OBJECT_0)
break;
FD_ZERO(&server_fd_set);
FD_SET(m_sServer, &server_fd_set); // 将监听 socket 添加到集合里
tv.tv_sec = 0;
tv.tv_usec = 0;
int ret = select(0, &server_fd_set, NULL, NULL, &tv); // 等待监听集合里所有的句柄
if (ret < 0) {
printf("Select error\n");
}
// 监听端口进来的连接信息
if (FD_ISSET(m_sServer, &server_fd_set)) { // 监听端口有可读数据
// 将端口监听进来
//struct sockaddr_in c_addr;
//int len = sizeof(c_addr);
//SOCKET client_socket = accept(m_sServer, (struct sockaddr*)&c_addr, &len);
SOCKADDR_IN addrServer = { 0 };
int iaddrLen = sizeof(addrServer);
SOCKET client_socket = accept(m_sServer, (SOCKADDR*)&addrServer, &iaddrLen); // 创建和客户端对应的 socket
if (client_socket != INVALID_SOCKET) {
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addrServer.sin_addr, str, sizeof(str));
TcpClient _tcp(client_socket, str, true);
m_TcpClient.push_back(_tcp);
printf("accept a connection from IP: %s,Port: %d\n", str, htons(addrServer.sin_port));
}
}
//查询是否有新的数据
fd_set readfdr;
for (int i = m_TcpClient.size() - 1; i >= 0; i--)
{
if (i >= (int)(m_TcpClient.size())) break;
if (!m_TcpClient[i].bConnect) continue;
FD_ZERO(&readfdr);
FD_SET(m_TcpClient[i].socket, &readfdr);
tv.tv_sec = 0;
tv.tv_usec = 0;
ret = select(0, &readfdr, NULL, NULL, &tv);
if ((ret > 0 && FD_ISSET(m_TcpClient[i].socket, &readfdr)))
{
ZeroMemory(pBuffer, sizeof(pBuffer));
retRead = recv(m_TcpClient[i].socket, pBuffer, 2048, 0);
if (retRead <= 0)
{
std::lock_guard<std::mutex> lock(m_mtx);
m_TcpClient[i].bConnect = false;
closesocket(m_TcpClient[i].socket);
m_TcpClient.erase(m_TcpClient.begin() + i);
continue;
}
else if (retRead > 0)
{
pBuffer[retRead] = '\0';
std::cout << "recv a message from IP: " << m_TcpClient[i].addr << std::endl
<< "content is: " << pBuffer << std::endl;
}
}
}
}
}
void TcpServer::send_msg(PVOID pM)
{
char* msg = (char*)pM;
std::lock_guard<std::mutex> lock(m_mtx);
for (unsigned int i = 0; i < m_TcpClient.size(); i++)
::send(m_TcpClient[i].socket, msg, strlen(msg), 0);
}
void TcpServer::send_msg(PVOID pM, int len)
{
std::lock_guard<std::mutex> lock(m_mtx);
for (unsigned int i = 0; i < m_TcpClient.size(); i++)
::send(m_TcpClient[i].socket, (char*)pM, len, 0);
}
结尾
写的还是比较粗糙,应该能用,希望有所帮助吧!## 标题