异步socket TCP 通信

异步socket TCP 通信

使用 WSAAsyncSelect 可实现异步 socket 通信,原型:

WSAAsyncSelect(
    SOCKET s,            //套接字
    HWND hWnd,        //接收网络事件的窗口句柄
    unsigned int wMsg,//网络事件通知消息
    long lWvent            //套接字需要的通知码
);

long lWvent 有:

  • FD_READ :接收到对方发送的数据包
  • FD_WRITE :可以写入数据
  • FD_ACCEPT :接收到链接请求
  • FD_CONNECT :socket成功链接到对方
  • FD_CLOSE :链接关闭

代码:
server:

BEGIN_MESSAGE_MAP(CAsyncSocketDlg, CDialogEx)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDOK, &CAsyncSocketDlg::OnBnClickedOk)
    ON_MESSAGE(WM_SOCKET_MSG, &CAsyncSocketDlg::OnSockMsg)
END_MESSAGE_MAP()

// CAsyncSocketDlg 消息处理程序
BOOL CAsyncSocketDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);         // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    m_listenSock = socket(PF_INET, SOCK_STREAM, 0);
    WSAAsyncSelect(m_listenSock, GetSafeHwnd(), WM_SOCKET_MSG, FD_ACCEPT);
    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.S_un.S_addr = ADDR_ANY;
    addr.sin_port = htons(9999);
    bind(m_listenSock, (SOCKADDR*)&addr, sizeof(addr));
    listen(m_listenSock, 5);
    m_edit.ShowScrollBar(SB_VERT, TRUE);

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
void CAsyncSocketDlg::OnBnClickedOk()
{
    closesocket(m_clientSock);
    closesocket(m_listenSock);
    WSACleanup();
    CDialogEx::OnOK();
}

LRESULT CAsyncSocketDlg::OnSockMsg(WPARAM wParam, LPARAM lParam)
{
    if (WSAGETSELECTERROR(lParam))
        return 0;
    CString msg;
    m_edit.GetWindowText(msg);
    switch (WSAGETSELECTEVENT(lParam))
    {
    case FD_ACCEPT:
    {
        SOCKADDR_IN addr;
        int size = sizeof(addr);
        m_clientSock = accept(m_listenSock, (SOCKADDR*)&addr, &size);
        WSAAsyncSelect(m_clientSock, GetSafeHwnd(), WM_SOCKET_MSG, FD_READ | FD_CLOSE);
        CString s;
        s.Format(_T("客户端地址:%s:%d\r\n"), inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        msg += s;
    }
        break;
    case FD_READ:
    {
        ZeroMemory(m_buf, sizeof(m_buf));
        recv(m_clientSock, m_buf, sizeof(m_buf), 0);
        msg = msg + "接收到:" + CString(m_buf) + "\r\n";
        CString s = CString("server send:") + CString(m_buf);
        send(m_clientSock, s, s.GetLength(), 0);
    }
        break;
    case FD_CLOSE:
    {
        closesocket(m_clientSock);
        msg += "客户端关闭连接\r\n";
    }
        break;
    default:
        break;
    }
    m_edit.SetWindowText(msg);
    m_edit.LineScroll(m_edit.GetLineCount() - 1, 0);
    return 0;
}

client:

BEGIN_MESSAGE_MAP(CAsyncSocketClientDlg, CDialogEx)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDOK, &CAsyncSocketClientDlg::OnBnClickedOk)
    ON_BN_CLICKED(IDC_CONNECT, &CAsyncSocketClientDlg::OnBnClickedConnect)
    ON_BN_CLICKED(IDC_SEND, &CAsyncSocketClientDlg::OnBnClickedSend)
    ON_MESSAGE(WM_SOCKET_MSG, &CAsyncSocketClientDlg::OnSockMsg)
END_MESSAGE_MAP()

// CAsyncSocketClientDlg 消息处理程序
BOOL CAsyncSocketClientDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);         // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    m_sock = socket(PF_INET, SOCK_STREAM, 0);
    m_edit.ShowScrollBar(SB_VERT, TRUE);
    m_editSend.ShowScrollBar(SB_VERT, TRUE);

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CAsyncSocketClientDlg::OnBnClickedOk()
{
    closesocket(m_sock);
    WSACleanup();
    CDialogEx::OnOK();
}

void CAsyncSocketClientDlg::OnBnClickedConnect()
{
    CString s;
    GetDlgItemText(IDC_CONNECT, s);
    if (s == "链接")
    {
        m_sock = socket(PF_INET, SOCK_STREAM, 0);
        WSAAsyncSelect(m_sock, GetSafeHwnd(), WM_SOCKET_MSG, FD_CONNECT | FD_CLOSE | FD_READ);
        SOCKADDR_IN addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        addr.sin_port = htons(9999);
        connect(m_sock,(SOCKADDR*)&addr, (sizeof(addr)));
        CString msg;
        m_edit.GetWindowText(msg);
        msg += "链接服务端\r\n";
        m_edit.SetWindowText(msg);
        SetDlgItemText(IDC_CONNECT, "断开");
    }
    else if (s == "断开")
    {
        closesocket(m_sock);
        SetDlgItemText(IDC_CONNECT, "链接");
        CString msg;
        m_edit.GetWindowText(msg);
        msg += "断开链接\r\n";
        m_edit.SetWindowText(msg);
    }
}

void CAsyncSocketClientDlg::OnBnClickedSend()
{
    CString s;
    m_editSend.GetWindowText(s);
    send(m_sock, s, s.GetLength(), 0);
}

LRESULT CAsyncSocketClientDlg::OnSockMsg(WPARAM wParam, LPARAM lParam)
{
    if (WSAGETSELECTERROR(lParam))
        return 0;
    CString msg;
    m_edit.GetWindowText(msg);
    switch (WSAGETSELECTEVENT(lParam))
    {
    case FD_CONNECT:
    {
        msg += "链接成功\r\n";
    }
    break;
    case FD_READ:
    {
        ZeroMemory(m_buf, sizeof(m_buf));
        recv(m_sock, m_buf, sizeof(m_buf), 0);
        msg = msg + "接收到:" + CString(m_buf) + "\r\n";
    }
    break;
    case FD_CLOSE:
    {
        closesocket(m_sock);
        msg += "服务端关闭连接\r\n";
    }
    break;
    default:
        break;
    }
    m_edit.SetWindowText(msg);
    m_edit.LineScroll(m_edit.GetLineCount() - 1, 0);
    return 0;
}

效果:
这里写图片描述
代码链接:
VS2015工程:http://download.csdn.net/detail/yangyang031213/9893803
https://github.com/yangyang0312/cpp/tree/master/windows/AsyncSocket

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TCP(Transmission Control Protocol)是Internet协议族中的一种传输层协议,用于在不可靠的网络环境中提供可靠的、基于字节流的通信服务。在Windows系统中,使用Winsock API进行TCP异步通信的控制台程序涉及以下几个关键步骤: 1. **初始化Winsock库**: 首先,你需要包含Winsock头文件,并调用`WSADATA wsaData;` 初始化结构和`WSAStartup()` 函数,以启动Winsock服务。 ```cpp #include <winsock2.h> #include <ws2tcpip.h> WSADATA wsaData; int result = WSAStartup(MAKEWORD(2, 2), &wsaData); if (result != 0) { // 处理错误,通常打印错误代码 } ``` 2. **定义套接字**: 使用`socket()`函数创建一个套接字,指定AF_INET(IPv4)和SOCK_STREAM(TCP流式)型。 ```cpp SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { // 处理错误 } ``` 3. **设置服务器地址**: 对于客户端程序,这通常是获取远程服务器的地址;对于服务器程序,则需要设置监听地址。 4. **连接或接受连接**: 对于客户端,使用`connect()`连接到服务器;服务器则需要调用`bind()`和`listen()`后,使用`accept()`接收连接。 5. **发送和接收数据**: 使用`send()`发送数据,`recv()`接收数据。异步操作通常通过提供回调函数来处理完成事件,而不是阻塞主线程。 6. **错误处理**: 在整个通信过程中,要检查返回值并处理可能出现的错误,如`WSAGetLastError()`。 7. **关闭连接和清理**: 一旦通信完成,调用`shutdown()`关闭套接字的部分或全部连接,然后使用`closesocket()`关闭套接字,最后调用`WSACleanup()`结束Winsock。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值