UDP-完成端口模型

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值