#pragma once
#define _WINSOCK_DEPRECATED_NO_WARNINGS
//#define FD_SETSIZE 1024
#include <winsock2.h>
#include <windows.h>
#include <string>
#include <mswsock.h>
#include <iostream>
#pragma comment(lib,"Mswsock.lib")
#pragma comment(lib,"ws2_32.lib")
using namespace std;
//自定义的消息值不能和系统消息冲突
#define WSAAsyncSelectMsg WM_USER +1
#define Sever_Port 10000
struct fd_es_set //事件模型
{
UINT count;
SOCKET sockall[1024];
HANDLE eventall[1024];
};
struct fd_win_set//消息模型
{
UINT count;
SOCKET sockall[1024];
};
struct fd_esIo_set //重叠IO事件模型
{
UINT count;
SOCKET sockall[1024];
OVERLAPPED IOeventall[1024];
};
#define WSA_MAX_STR 548
struct udp_msg
{
char _recvstr[WSA_MAX_STR]; //recv消息用的
sockaddr_in SenderAddr;
};
struct fd_FinshIo_set //完成端口模型
{
SOCKET socketserver;
OVERLAPPED IOeventall;
HANDLE Port; //完成端口
PHANDLE Pthread; //保存的线程指针
DWORD ThreadNum; //系统的线程数量
BOOL ThreadOpen; //线程开关
udp_msg UdpMsg;
};
#include "main.h"
bool PostRecvFrom();
bool PostSendto(sockaddr_in SenderAddr, string sendmsg);
fd_FinshIo_set allsock;
VOID Server_write_error()
{
}
void clear()
{
//释放线程句柄
for (UINT i = 0; i < allsock.ThreadNum; i++)
{
CloseHandle(allsock.Pthread[i]);
}
//释放内存
free(allsock.Pthread);
/*释放整个结构体,可能有些事件和socket已经被释放过了,不影响*/
{
//释放stocket
closesocket(allsock.socketserver);
//关闭事件对象
WSACloseEvent(allsock.IOeventall.hEvent);
}
//清理网络库
WSACleanup();
}
//线程用于接收回调
DWORD WINAPI PTHREAD_ROUTINE(LPVOID lpThreadParameter)
{
_Out_ DWORD lpNumberOfBytes; //字节数
_Out_ ULONG_PTR lpCompletionKey; //绑定函数CreateIoCompletionPort传来的参数3
_Out_ LPOVERLAPPED lpOverlapped; //重叠结构
//取通知信息,无信息会自动挂起线程
while (allsock.ThreadOpen)
{// 参数3是传入参数,发给函数GetQueuedCompletionStatus的参数3
bool ret = GetQueuedCompletionStatus(allsock.Port, &lpNumberOfBytes, &lpCompletionKey, &lpOverlapped, INFINITE);
//if (false == ret)
//{
// printf("error_GetQueuedCompletionStatus\n");
// continue;
//}
{//客户端消息
if (0 != allsock.UdpMsg._recvstr[0])
{//recv
printf("%d.%d.%d.%d:%d\n", allsock.UdpMsg.SenderAddr.sin_addr.S_un.S_un_b.s_b1, allsock.UdpMsg.SenderAddr.sin_addr.S_un.S_un_b.s_b2, allsock.UdpMsg.SenderAddr.sin_addr.S_un.S_un_b.s_b3, allsock.UdpMsg.SenderAddr.sin_addr.S_un.S_un_b.s_b4, allsock.UdpMsg.SenderAddr.sin_port);
printf("recv:%s\n", allsock.UdpMsg._recvstr);
memset(allsock.UdpMsg._recvstr, 0, sizeof(allsock.UdpMsg._recvstr));
string sedmsg = "服务器收到";
PostSendto(allsock.UdpMsg.SenderAddr, sedmsg);
//继续传递
PostRecvFrom();
}
else
{//send
//printf("sendok\n");
//PostSend(lpCompletionKey);
}
}
}
return 1;
}
bool PostSendto(sockaddr_in SenderAddr, string sendmsg)
{
WSABUF lpBuffers = { (ULONG)sendmsg.length() ,(char*)sendmsg.c_str() };
DWORD lpNumberOfBytesRecvd;
DWORD flag = 0;
int SenderAddrSize = sizeof(SenderAddr);
int ret = WSASendTo(allsock.socketserver, //接收端socket
&lpBuffers, //接收的缓冲区
1, //参数二的个数
&lpNumberOfBytesRecvd, //接收成功的话保存接收字节数量
flag, //recv参数5,默认0
(sockaddr*)&SenderAddr, //接收的发送端信息
SenderAddrSize, //接收的发送端信息大小
&allsock.IOeventall, //IO重叠结构
0 //完成例程的回调函数 完成端口不需要
);
int error = WSAGetLastError();
if (ERROR_IO_PENDING != error)
{//函数执行出错
return 0;
}
return 1;
}
bool PostRecvFrom()
{
WSABUF lpBuffers = { sizeof(allsock.UdpMsg._recvstr) ,allsock.UdpMsg._recvstr };
DWORD lpNumberOfBytesRecvd;
DWORD flag = 0;
INT lpFromlen = 0;
int SenderAddrSize = sizeof(sockaddr);
int ret = WSARecvFrom(allsock.socketserver, //接受的客户端socket
&lpBuffers, //接收的缓冲区
1, //参数二的个数
&lpNumberOfBytesRecvd, //接收成功的话保存接收字节数量
&flag, //recv参数5,默认0
(sockaddr*)&allsock.UdpMsg.SenderAddr, //接收的发送端信息
&SenderAddrSize, //接收的发送端信息大小
&allsock.IOeventall, //IO重叠结构
0 //完成例程的回调函数 完成端口不需要
);
int error = WSAGetLastError();
if (ERROR_IO_PENDING != error)
{//函数执行出错
return 0;
}
return 1;
}
/*1.打开网络库
* 2.校验网络库版本
* 3.创建SOCKET
* 4.绑定IP地址和端口
* 5.创建完成端口,并绑定客户端socket/和完成端口
* 6.开始监听
* 7.开始异步接收accept recv
*/
int create()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* 使用Windef.h中声明的MAKEWORD(低字节、高字节)宏 */
wVersionRequested = MAKEWORD(2, 2);
/*启用网络链接库,调用的封装库命令*/
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return -1;
}
/*确认WinSock DLL支持2.2*/
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
//清理网络库
WSACleanup();
return -1;
}
//创建套接字。 创建网络类型 tcp或者upd
SOCKET socketServer = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == socketServer)
{
string ret = to_string(WSAGetLastError());
MessageBoxA(0, "error_socket", ret.c_str(), 0);
//清理网络库
WSACleanup();
return -1;
}
//设置sockaddr结构
sockaddr_in saServer;
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = INADDR_ANY;
saServer.sin_port = htons(Sever_Port);
// 绑定本机(服务器)IP和端口
//sockaddr结构中的信息
if (SOCKET_ERROR == bind(socketServer, (SOCKADDR*)&saServer, sizeof(saServer)))
{
string ret = to_string(WSAGetLastError());
MessageBoxA(0, "error_bind", ret.c_str(), 0);
//释放stocket
closesocket(socketServer);
//清理网络库
WSACleanup();
return -1;
}
/*将服务器socket和事件对象句柄写进结构体*/
allsock.IOeventall.hEvent = WSACreateEvent();;
allsock.socketserver = socketServer;
//创建一个完成端口
allsock.Port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
if (0 == allsock.Port)
{
string ret = to_string(WSAGetLastError());
MessageBoxA(0, "error_listen", ret.c_str(), 0);
//释放stocket
closesocket(socketServer);
//清理网络库
WSACleanup();
return -1;
}
//绑定sorket 和 完成端口 参数3是传入参数,发给函数GetQueuedCompletionStatus的参数3
if (0 == CreateIoCompletionPort((HANDLE)allsock.socketserver, allsock.Port, 0, 0))
{
string ret = to_string(WSAGetLastError());
MessageBoxA(0, "error_listen", ret.c_str(), 0);
CloseHandle(allsock.Port);
//释放stocket
closesocket(socketServer);
//清理网络库
WSACleanup();
return -1;
}
if(0 == PostRecvFrom())
{
string ret = to_string(WSAGetLastError());
MessageBoxA(0, "error_PostRecvFrom", ret.c_str(), 0);
CloseHandle(allsock.Port);
//释放stocket
closesocket(socketServer);
//清理网络库
WSACleanup();
return -1;
}
//创建线程,查询CPU是几核就创建几核
SYSTEM_INFO lpSystemInfo;
GetSystemInfo(&lpSystemInfo);
allsock.ThreadNum = lpSystemInfo.dwNumberOfProcessors;
allsock.Pthread = (PHANDLE)malloc(allsock.ThreadNum * sizeof(HANDLE));
allsock.ThreadOpen = true;
/*创建线程来用于消息接收*/
for (UINT i = 0; i < allsock.ThreadNum; i++)
{
allsock.Pthread[i] = CreateThread(0, 0, PTHREAD_ROUTINE, 0, 0, 0);
}
while (allsock.ThreadOpen)
{
Sleep(1000);
}
return 1;
}
BOOL WINAPI HANDLER_ROUTINE(_In_ DWORD CtrlType)
{
switch (CtrlType)
{
case CTRL_CLOSE_EVENT:
{
allsock.ThreadOpen = false;
clear();
}
default:
break;
}
return true;
}
int main()
{
//创建个回调监视控制台关闭
SetConsoleCtrlHandler(HANDLER_ROUTINE, true);
create();
// create("127.0.0.1");
return 0;
}
客户发送端用C/S模型即可
#include "main.h"
SOCKET socket_This_Device;//本机socket
LONG64 write_error()
{
return 1;
}
int create(const char* ServerIpAdress)
{
/*接收信息,主要是高低版本信息*/
WSADATA wsaData;
/* 使用Windef.h中声明的MAKEWORD(低字节、高字节)宏 */
WORD wVersionRequested = MAKEWORD(2, 2);
/*启用网络链接库,调用的封装库命令*/
if (0 != WSAStartup(wVersionRequested, &wsaData))
{
write_error();
}
/*确认WinSock DLL支持2.2*/
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
write_error();
//清理网络库
WSACleanup();
}
//创建套接字。 创建网络类型 tcp或者upd
socket_This_Device = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (INVALID_SOCKET == socket_This_Device)
{
write_error();
//清理网络库
WSACleanup();
}
设置本设备的sockaddr结构
//sockaddr_in saThis_Device;
//saThis_Device.sin_family = AF_INET;
//saThis_Device.sin_addr.s_addr = inet_addr(ServerIpAdress);
//saThis_Device.sin_port = htons(3000);
使用绑定侦听套接字 将本机地址和端口号绑定到socket 如果不作为接收端,这一步可以省略
//if (SOCKET_ERROR == bind(socket_This_Device, (SOCKADDR*)&saThis_Device, sizeof(saThis_Device)))
//{
// string ret = to_string(WSAGetLastError());
// MessageBoxA(0, ret.c_str(), "error_bind", 0);
// //释放stocket
// closesocket(socket_This_Device);
// //清理网络库
// WSACleanup();
// return -1;
//}
//设置sockaddr结构 接收端地址和端口号
sockaddr_in saOtherDevice;
saOtherDevice.sin_family = AF_INET;
saOtherDevice.sin_addr.s_addr = inet_addr(ServerIpAdress);
saOtherDevice.sin_port = htons(10000);
while (true)
{
/*本设备发送消息给其它IP*/
char sendbuff[548] = {0};
scanf_s("%s", sendbuff, sizeof(sendbuff));
int sendto_ret = sendto(socket_This_Device, sendbuff, strlen(sendbuff), 0, (sockaddr*)&saOtherDevice, sizeof(saOtherDevice));
if (SOCKET_ERROR == sendto_ret)
{
write_error();
}
/*接收字符串和发送端设备的IP和端口,类似TCP的revc*/
char Getbuff[548] = { 0 };
sockaddr_in saGetDeviceMsg = { 0 };
int saGetDeviceMsgSize = sizeof(sockaddr);
int recvfrom_ret = recvfrom(socket_This_Device, Getbuff, sizeof(Getbuff), 0, (sockaddr*)&saGetDeviceMsg, &saGetDeviceMsgSize);
if (SOCKET_ERROR == recvfrom_ret)
{
write_error();
}
printf("ClientIp:%d.%d.%d.%d:%d \n Buff:%s\n\n",
saGetDeviceMsg.sin_addr.S_un.S_un_b.s_b1,
saGetDeviceMsg.sin_addr.S_un.S_un_b.s_b2,
saGetDeviceMsg.sin_addr.S_un.S_un_b.s_b3,
saGetDeviceMsg.sin_addr.S_un.S_un_b.s_b4,
ntohs(saGetDeviceMsg.sin_port),
Getbuff);
Sleep(3);
}
system("pause");
//释放stocket
closesocket(socket_This_Device);
//清理网络库
WSACleanup();
}
int main()
{
create("192.168.31.55");
return 1;
}