消息,事件,完成端口
// 00.TCP_CLIENT.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
// 1. 包含头文件及库 要写在其他头文件(类似windows.h)之前
#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib")
DWORD WINAPI RecvThread(LPVOID lParam) {
SOCKET sClient = (SOCKET)lParam;
while (true)
{
char buf[1024] = {};
int nRet = recv(sClient, buf, 1024, NULL);
if (nRet == SOCKET_ERROR) {
printf("服务器关闭\n");
exit(0);
return 0;
}
printf("%s\n", buf);
}
return 0;
}
int main()
{ // 1. 信号检测
WSADATA wsd = {};
WSAStartup(MAKEWORD(2, 2), &wsd);
if (LOBYTE(wsd.wVersion) != 2 ||
HIBYTE(wsd.wVersion) != 2)
{
printf("库版本不支持\n");
return 0;
}
// 2. 买手机
SOCKET sClient = socket(
AF_INET,// IP4协议
SOCK_STREAM,// 流式套接字
IPPROTO_TCP);// 协议类型(TCP)
if (sClient == INVALID_SOCKET)
{
printf("创建socket失败!\n");
WSACleanup();
return 0;
}
// 3. 办卡
SOCKADDR_IN addrSer = {};
addrSer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSer.sin_port = htons(0x1234);// host to net short
addrSer.sin_family = AF_INET;
int nLen = sizeof(SOCKADDR_IN);
// 绑定+通讯 直接和服务器通讯,自动绑定
int nRet = connect(sClient, (SOCKADDR*)&addrSer, nLen);
if (nRet == SOCKET_ERROR) { /*清理环境 关闭套接字*/return 0; }
CreateThread(NULL, NULL, RecvThread, (LPVOID)sClient, NULL, NULL);
while (true)
{
char buf[1024] = {};
scanf_s("%s", buf, 1024);
nRet = send(sClient, buf, 1024, NULL);
if (nRet == SOCKET_ERROR)
{
closesocket(sClient);
WSACleanup();
return 0;
}
}
return 0;
}
===================
#pragma once
#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib")
#include <vector>
using std::vector;
class CMyTCP
{
public:
CMyTCP();
~CMyTCP();
SOCKET m_socket;
vector<SOCKET> m_vecSocket;
SOCKET TcpAccept();
int TcpRecv(SOCKET s,char*buf,int nLen);
bool InitServer(char* pIp="127.0.0.1",short port=0x1234);
bool TcpClientExit(SOCKET s);
};
#include "stdafx.h"
#include "MyTCP.h"
CMyTCP::CMyTCP()
{
}
CMyTCP::~CMyTCP()
{
}
SOCKET CMyTCP::TcpAccept()
{
SOCKADDR addr = {};
int nLen = sizeof(SOCKADDR);
SOCKET s = accept(m_socket, &addr, &nLen);
if (s == INVALID_SOCKET)
{
return INVALID_SOCKET;
}
m_vecSocket.push_back(s);
return s;
}
int CMyTCP::TcpRecv(SOCKET s, char*buf, int nLen)
{
int nRet = recv(s, buf, nLen,NULL);
if (nRet == SOCKET_ERROR) return nRet;
for (auto &each:m_vecSocket)
{
if(each == s) continue;
send(each, buf, nLen, NULL);
}
return nRet;
}
bool CMyTCP::InitServer(char* pIp/*="127.0.0.1"*/, short port/*=0x1234*/)
{
// 1. 信号检测
WSADATA wsd = {};
WSAStartup(MAKEWORD(2, 2), &wsd);
if (LOBYTE(wsd.wVersion) != 2 ||
HIBYTE(wsd.wVersion) != 2)
{
printf("库版本不支持\n");
return 0;
}
// 2. 买手机
m_socket = socket(
AF_INET,// IP4协议
SOCK_STREAM,// 流式套接字
IPPROTO_TCP);// 协议类型(TCP)
if (m_socket == INVALID_SOCKET)
{
printf("创建socket失败!\n");
WSACleanup();
return 0;
}
// 3. 办卡
SOCKADDR_IN addrSer = {};
addrSer.sin_addr.S_un.S_addr = inet_addr(pIp);
addrSer.sin_port = htons(port);// host to net short
addrSer.sin_family = AF_INET;
int nLen = sizeof(SOCKADDR_IN);
int nRet = bind(m_socket, (SOCKADDR*)&addrSer, nLen);
if (nRet == SOCKET_ERROR) {/*关闭套接字,清理环境*/return 0; }
// 4. 监听
nRet = listen(m_socket, SOMAXCONN);
if (nRet == SOCKET_ERROR) {/*关闭套接字,清理环境*/return 0; }
return true;
}
bool CMyTCP::TcpClientExit(SOCKET s)
{
for (int i=0;i<m_vecSocket.size();i++)
{
if (m_vecSocket[i] == s)
{
m_vecSocket.erase(m_vecSocket.begin() + i);
closesocket(s);
return true;
}
}
return false;
}
#pragma once
#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib")
#include <vector>
using std::vector;
class CMyTCP
{
public:
CMyTCP();
~CMyTCP();
SOCKET m_socket;
vector<SOCKET> m_vecSocket;
SOCKET TcpAccept();
int TcpRecv(SOCKET s,char*buf,int nLen);
bool InitServer(char* pIp="127.0.0.1",short port=0x1234);
bool TcpClientExit(SOCKET s);
};
#include "stdafx.h"
#include "MyTCP.h"
CMyTCP::CMyTCP()
{
}
CMyTCP::~CMyTCP()
{
}
SOCKET CMyTCP::TcpAccept()
{
SOCKADDR addr = {};
int nLen = sizeof(SOCKADDR);
SOCKET s = accept(m_socket, &addr, &nLen);
if (s == INVALID_SOCKET)
{
return INVALID_SOCKET;
}
m_vecSocket.push_back(s);
return s;
}
int CMyTCP::TcpRecv(SOCKET s, char*buf, int nLen)
{
int nRet = recv(s, buf, nLen,NULL);
if (nRet == SOCKET_ERROR) return nRet;
for (auto &each:m_vecSocket)
{
if(each == s) continue;
send(each, buf, nLen, NULL);
}
return nRet;
}
bool CMyTCP::InitServer(char* pIp/*="127.0.0.1"*/, short port/*=0x1234*/)
{
// 1. 信号检测
WSADATA wsd = {};
WSAStartup(MAKEWORD(2, 2), &wsd);
if (LOBYTE(wsd.wVersion) != 2 ||
HIBYTE(wsd.wVersion) != 2)
{
printf("库版本不支持\n");
return 0;
}
// 2. 买手机
m_socket = socket(
AF_INET,// IP4协议
SOCK_STREAM,// 流式套接字
IPPROTO_TCP);// 协议类型(TCP)
if (m_socket == INVALID_SOCKET)
{
printf("创建socket失败!\n");
WSACleanup();
return 0;
}
// 3. 办卡
SOCKADDR_IN addrSer = {};
addrSer.sin_addr.S_un.S_addr = inet_addr(pIp);
addrSer.sin_port = htons(port);// host to net short
addrSer.sin_family = AF_INET;
int nLen = sizeof(SOCKADDR_IN);
int nRet = bind(m_socket, (SOCKADDR*)&addrSer, nLen);
if (nRet == SOCKET_ERROR) {/*关闭套接字,清理环境*/return 0; }
// 4. 监听
nRet = listen(m_socket, SOMAXCONN);
if (nRet == SOCKET_ERROR) {/*关闭套接字,清理环境*/return 0; }
return true;
}
bool CMyTCP::TcpClientExit(SOCKET s)
{
for (int i=0;i<m_vecSocket.size();i++)
{
if (m_vecSocket[i] == s)
{
m_vecSocket.erase(m_vecSocket.begin() + i);
closesocket(s);
return true;
}
}
return false;
}
// 02.TCP_SER_EVENT.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "MyTCP.h"
int main()
{
vector<HANDLE> m_vecEvent;
vector<SOCKET> m_vecSocket;
CMyTCP tcp;
tcp.InitServer();
HANDLE hEvent = WSACreateEvent();
m_vecEvent.push_back(hEvent);
// 当m_socket需要响应FD_ACCEPT | FD_CLOSE事件时
// 系统会激活hEvent,把它变成有信号状态
WSAEventSelect(tcp.m_socket, hEvent, FD_ACCEPT | FD_CLOSE);
m_vecSocket.push_back(tcp.m_socket);
while (true)
{
int nCount = m_vecEvent.size();
// nCount不能超过64
int nRet = WSAWaitForMultipleEvents(
nCount,// 等待的事件个数 HEVENT
&m_vecEvent[0], // 等待的多个事件的数组地址
FALSE, // 是否等待所有事件都被激活
INFINITE,// 等待超时时间
FALSE);// 是否可警醒
if (nRet == WSA_WAIT_FAILED) continue;
int nIndex = nRet - WSA_WAIT_EVENT_0;
// 获取被激活的事件对应的socket的网络事件
WSANETWORKEVENTS we = {};
WSAEnumNetworkEvents(m_vecSocket[nIndex], m_vecEvent[nIndex], &we);
if (we.lNetworkEvents & FD_ACCEPT)
{
SOCKET s = tcp.TcpAccept();
HANDLE hEvent2 = WSACreateEvent();
m_vecEvent.push_back(hEvent2);
// 当m_socket需要响应FD_ACCEPT | FD_CLOSE事件时
// 系统会激活hEvent,把它变成有信号状态
WSAEventSelect(s, hEvent2, FD_READ | FD_CLOSE);
m_vecSocket.push_back(s);
}
if (we.lNetworkEvents & FD_READ)
{
char buf[1024] = {};
tcp.TcpRecv(m_vecSocket[nIndex], buf, 1024);
printf("%s\n", buf);
}
if (we.lNetworkEvents & FD_CLOSE)
{
if (we.iErrorCode[FD_CLOSE_BIT] != 0)
printf("客户端流氓式关闭\n");
else
{
printf("客户端退出\n");
}
tcp.TcpClientExit(m_vecSocket[nIndex]);
}
}
return 0;
}
=========================
#pragma once
#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib")
#include <vector>
using std::vector;
class CMyTCP
{
public:
CMyTCP();
~CMyTCP();
SOCKET m_socket;
vector<SOCKET> m_vecSocket;
SOCKET TcpAccept();
int TcpRecv(SOCKET s,char*buf,int nLen);
bool InitServer(char* pIp="127.0.0.1",short port=0x1234);
bool TcpClientExit(SOCKET s);
};
#include "stdafx.h"
#include "MyTCP.h"
CMyTCP::CMyTCP()
{
}
CMyTCP::~CMyTCP()
{
}
SOCKET CMyTCP::TcpAccept()
{
SOCKADDR addr = {};
int nLen = sizeof(SOCKADDR);
SOCKET s = accept(m_socket, &addr, &nLen);
if (s == INVALID_SOCKET)
{
return INVALID_SOCKET;
}
m_vecSocket.push_back(s);
return s;
}
int CMyTCP::TcpRecv(SOCKET s, char*buf, int nLen)
{
for (auto &each:m_vecSocket)
{
if(each == s) continue;
send(each, buf, nLen, NULL);
}
return true;
}
bool CMyTCP::InitServer(char* pIp/*="127.0.0.1"*/, short port/*=0x1234*/)
{
// 1. 信号检测
WSADATA wsd = {};
WSAStartup(MAKEWORD(2, 2), &wsd);
if (LOBYTE(wsd.wVersion) != 2 ||
HIBYTE(wsd.wVersion) != 2)
{
printf("库版本不支持\n");
return 0;
}
// 2. 买手机
m_socket = socket(
AF_INET,// IP4协议
SOCK_STREAM,// 流式套接字
IPPROTO_TCP);// 协议类型(TCP)
if (m_socket == INVALID_SOCKET)
{
printf("创建socket失败!\n");
WSACleanup();
return 0;
}
// 3. 办卡
SOCKADDR_IN addrSer = {};
addrSer.sin_addr.S_un.S_addr = inet_addr(pIp);
addrSer.sin_port = htons(port);// host to net short
addrSer.sin_family = AF_INET;
int nLen = sizeof(SOCKADDR_IN);
int nRet = bind(m_socket, (SOCKADDR*)&addrSer, nLen);
if (nRet == SOCKET_ERROR) {/*关闭套接字,清理环境*/return 0; }
// 4. 监听
nRet = listen(m_socket, SOMAXCONN);
if (nRet == SOCKET_ERROR) {/*关闭套接字,清理环境*/return 0; }
return true;
}
bool CMyTCP::TcpClientExit(SOCKET s)
{
for (int i=0;i<m_vecSocket.size();i++)
{
if (m_vecSocket[i] == s)
{
m_vecSocket.erase(m_vecSocket.begin() + i);
closesocket(s);
return true;
}
}
return false;
}
// 03.TCP_SER_IOCP.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "MyTCP.h"
#include <windows.h>
CMyTCP g_tcp;
typedef struct _MYOVERLAPPED
{
OVERLAPPED ol;
WSABUF wsa;
char buf[1024];
}MYOVERLAPPED,*PMYOVERLAPPED;
DWORD WINAPI IOCP_Thread(LPVOID lParam) {
HANDLE hIOCP = lParam;
while (true)
{
DWORD dwTransfered = 0;// 传输的字节数
DWORD dwCompleteKey = 0;// 完成键
PMYOVERLAPPED mol = 0;
int nRet = GetQueuedCompletionStatus(
hIOCP, &dwTransfered, &dwCompleteKey, (LPOVERLAPPED*)&mol, INFINITE);
if (nRet == NULL && GetLastError() == ERROR_ABANDONED_WAIT_0)
{
printf("完成端口被关闭\n");
return 0;
}
if (nRet == NULL && dwCompleteKey)
{
g_tcp.TcpClientExit(dwCompleteKey);
printf("客户端退出\n");
continue;
}
// 处理recv
g_tcp.TcpRecv(dwCompleteKey, mol->buf, 1024);
printf("%s\n", mol->buf);
ZeroMemory(mol, sizeof(MYOVERLAPPED));
mol->wsa.buf = mol->buf;
mol->wsa.len = 1024;
DWORD dwFlags = 0;
WSARecv(
dwCompleteKey,
&mol->wsa,//读取的数据放在哪
1,// 伪大小,把recv操作交给完成端口
NULL,// 实际读取的大小,有OVERLAPPED不需要它
&dwFlags,
(LPOVERLAPPED)mol, NULL);
}
return 0;
}
int main()
{
// 1 准备好完成端口
SYSTEM_INFO si = {};
GetSystemInfo(&si);
HANDLE hIOCP = CreateIoCompletionPort(
INVALID_HANDLE_VALUE, NULL, NULL, si.dwNumberOfProcessors);
// 2. 完成端口的服务线程
for (int i = 0; i < si.dwNumberOfProcessors*2; i++)
{
CreateThread(
NULL, NULL, IOCP_Thread, hIOCP, NULL, NULL);
}
// 3. 绑定设备(socket)
g_tcp.InitServer();
while (true)
{
SOCKET sClient = g_tcp.TcpAccept();
if (sClient == INVALID_SOCKET) return 0;
// 把客户端socket和完成端口绑定
CreateIoCompletionPort((HANDLE)sClient, hIOCP, sClient, NULL);
PMYOVERLAPPED mol = new MYOVERLAPPED{};
mol->wsa.buf = mol->buf;
mol->wsa.len = 1024;
DWORD dwFlags = 0;
WSARecv(
sClient,
&mol->wsa,//读取的数据放在哪
1,// 伪大小,把recv操作交给完成端口
NULL,// 实际读取的大小,有OVERLAPPED不需要它
&dwFlags,
(LPOVERLAPPED)mol, NULL);
}
return 0;
}