socket TCP 通信

本文提供了一个TCP通信的具体实现案例,包括服务器端与客户端的代码。详细介绍了如何使用Winsock进行TCP通信,涵盖了创建套接字、连接、监听及数据收发等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

socket TCP 通信

SOCKET可用于主机间或者进程间通信等。
TCP/UDP通信流程:
这里写图片描述
代码(本机TCP):
Server:

//启动监听线程
void CSocketDlg::OnBnClickedStart()
{
    m_run = TRUE;
    if (!AfxBeginThread(CSocketDlg::StartRecvThread, this, THREAD_PRIORITY_ABOVE_NORMAL))
    {
        OutputDebugString("func:AfxBeginThread StartRecvThread failed");
        return;
    }
}
//停止监听线程
void CSocketDlg::OnBnClickedStop()
{
    m_run = FALSE;
    SOCKADDR_IN addr;
    addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8101);
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);//因为accept阻塞的,这样能够正常退出监听线程
    CString msg;
    connect(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR));
    closesocket(sock);
}
//监听线程
UINT CSocketDlg::StartRecvThread(LPVOID para)
{
    //创建套接字
    WORD myVersionRequest;
    WSADATA wsaData;
    myVersionRequest = MAKEWORD(2, 2);
    int err;
    err = WSAStartup(myVersionRequest, &wsaData);
    if (err != 0)
    {
        CString s;
        s.Format(_T("func:WSAStartup failed,error:%d"), GetLastError());
        OutputDebugString(s);
        char cstrNewDosCmd[] = "netsh.exe winsock reset";
        STARTUPINFO si;
        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
        GetStartupInfo(&si);
        si.wShowWindow = SW_HIDE;
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        PROCESS_INFORMATION pi;
        // 启动进程  
        DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
        BOOL bSuc = CreateProcess(NULL, cstrNewDosCmd, NULL, NULL, TRUE, dwCreationFlag, NULL, NULL, &si, &pi);
        WaitForSingleObject(pi.hProcess, 5000);
        err = WSAStartup(myVersionRequest, &wsaData);
        if (err != 0)
            return 0;
    }
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        CString s;
        s.Format(_T("func:WSAStartup version not ok,error:%d"), GetLastError());
        OutputDebugString(s);
        WSACleanup();
        return 0;
    }

    SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);//创建了可识别套接字
    SOCKADDR_IN listenAddr;
    listenAddr.sin_family = AF_INET;
    listenAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//ip地址
    listenAddr.sin_port = htons(8101);//绑定端口
    int flag = 1;
    int len = sizeof(int);
    if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&flag, len) == -1)
    {
        CString s;
        s.Format(_T("set reuse recvSock IP:%s port:%d failed ,error:%d"), inet_ntoa(listenAddr.sin_addr), listenAddr.sin_port, WSAGetLastError());
        OutputDebugString(s);
    }
    if (SOCKET_ERROR == bind(listenSocket, (SOCKADDR*)&listenAddr, sizeof(SOCKADDR)))
    {
        CString s;
        s.Format(_T("bind recvSock IP:%s port:%d failed ,error:%d"), inet_ntoa(listenAddr.sin_addr), listenAddr.sin_port, WSAGetLastError());
        OutputDebugString(s);
        closesocket(listenSocket);
        WSACleanup();
        return 0;
    }
    if (SOCKET_ERROR == listen(listenSocket, 5))
    {
        CString s;
        s.Format(_T("listen recvSock IP:%s port:%d failed ,error:%d"), inet_ntoa(listenAddr.sin_addr), listenAddr.sin_port, WSAGetLastError());
        OutputDebugString(s);
        closesocket(listenSocket);
        WSACleanup();
        return 0;
    }
    OutputDebugString("StartRecvThread OK");
    CSocketDlg * pParent = (CSocketDlg *)para;
    SOCKADDR_IN clientsocket;
    int AddrLen = sizeof(SOCKADDR);
    TCHAR recvBuf[4096];
    while (pParent->m_run)
    {
        ZeroMemory(recvBuf, 4096);
        SOCKET serConn = accept(listenSocket, (SOCKADDR*)&clientsocket, &AddrLen);
        if (serConn == INVALID_SOCKET)
        {
            CString msg;
            msg.Format("server sccept error:%d", WSAGetLastError());
            OutputDebugString(msg);
            continue;
        }
        OutputDebugString("server StartRecvThread accept");
        int recvLen = recv(serConn, recvBuf, 4096, 0);
        OutputDebugString(recvBuf);
        if (recvLen < 1)
        {
            CString msg;
            msg.Format("server recv error:%d", WSAGetLastError());
            OutputDebugString(msg);
            closesocket(serConn);//关闭
            continue;
        }
        CString sendText;
        pParent->m_editSend.GetWindowText(sendText);
        SOCKADDR_IN sendAddr;
        sendAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        sendAddr.sin_family = AF_INET;
        sendAddr.sin_port = htons(8102);
        if (SOCKET_ERROR != send(serConn, sendText, sendText.GetLength(), 0))
        {
            OutputDebugString("server send ok");
        }
        else
        {
            OutputDebugString("server send error");
        }
        CString text;
        pParent->m_edit.GetWindowText(text);
        text = text+ "接收到:"+CString(recvBuf)+"\r\n"+"发送:"+sendText+"\r\n";
        pParent->m_edit.SetWindowText(text);
        pParent->m_edit.LineScroll(pParent->m_edit.GetLineCount() - 1, 0);
        closesocket(serConn);//关闭
    }
    closesocket(listenSocket);
    WSACleanup();
    OutputDebugString("StartRecvThread STOP");
    return 0;
}

Client:

void CSocketClientDlg::OnBnClickedSend()
{//创建套接字
    WORD myVersionRequest;
    WSADATA wsaData;
    myVersionRequest = MAKEWORD(2, 2);
    int err;
    err = WSAStartup(myVersionRequest, &wsaData);
    if (err != 0)
    {
        CString s;
        s.Format(_T("func:WSAStartup failed,error:%d"), GetLastError());
        OutputDebugString(s);
        char cstrNewDosCmd[] = "netsh.exe winsock reset";
        STARTUPINFO si;
        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
        GetStartupInfo(&si);
        si.wShowWindow = SW_HIDE;
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        PROCESS_INFORMATION pi;
        // 启动进程  
        DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
        BOOL bSuc = CreateProcess(NULL, cstrNewDosCmd, NULL, NULL, TRUE, dwCreationFlag, NULL, NULL, &si, &pi);
        WaitForSingleObject(pi.hProcess, 5000);
        err = WSAStartup(myVersionRequest, &wsaData);
        if (err != 0)
            return;
    }
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        CString s;
        s.Format(_T("func:WSAStartup version not ok,error:%d"), GetLastError());
        OutputDebugString(s);
        WSACleanup();
        return;
    }
    OutputDebugString("CSocketClientDlg StartSendThread OK");
    SOCKADDR_IN sendAddr;
    sendAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    sendAddr.sin_family = AF_INET;
    sendAddr.sin_port = htons(8101);
    CString sendText;
    m_editSend.GetWindowText(sendText);
    SOCKET SendSocket = socket(AF_INET, SOCK_STREAM, 0);//创建了可识别套接字
    CString msg;
    if (SOCKET_ERROR != connect(SendSocket, (SOCKADDR*)&sendAddr, sizeof(SOCKADDR)))
    {
        if (SOCKET_ERROR != send(SendSocket, sendText.GetBuffer(), sendText.GetLength(), 0))
        {
            OutputDebugString("CSocketClientDlg client send ok");
            char recvBuf[4096] = { 0 };
            if (recv(SendSocket, recvBuf, 4096, 0) > 0)
            {
                CString recvText;
                m_editRecv.GetWindowText(recvText);
                recvText = recvText + "client recv: " + CString(recvBuf) + "\r\n";
                m_editRecv.SetWindowText(recvText);
                m_editRecv.LineScroll(m_editRecv.GetLineCount()-1, 0);//CEdit自动滚动
            }
            else
            {
                msg.Format("CSocketClientDlg recv error:%d", WSAGetLastError());
                OutputDebugString(msg);
            }
        }
        else
        {
            msg.Format("CSocketClientDlg StartSendThread send error:%d", WSAGetLastError());
            OutputDebugString(msg);
        }
    }
    else
    {
        msg.Format("CSocketClientDlg connect error:%d", WSAGetLastError());
        OutputDebugString(msg);
    }
    closesocket(SendSocket);
    WSACleanup();
    return;
}

几个点:

m_editRecv.LineScroll(m_editRecv.GetLineCount()-1, 0);//CEdit自动滚动到最后一行
m_editSend.ShowScrollBar(SB_VERT, TRUE);//CEdit加上垂直滚动条
//accept阻塞,可以链接一下让它退出
SOCKADDR_IN addr;
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(8101);
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
CString msg;
connect(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR));
closesocket(sock);
//有时候WSAStartup失败,可以重试下,或者执行下netsh winsock reset
CString s;
s.Format(_T("func:WSAStartup failed,error:%d"), GetLastError());
OutputDebugString(s);
char cstrNewDosCmd[] = "netsh.exe winsock reset";
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
BOOL bSuc = CreateProcess(NULL, cstrNewDosCmd, NULL, NULL, TRUE, dwCreationFlag, NULL, NULL, &si, &pi);// 启动进程  
WaitForSingleObject(pi.hProcess, 5000);

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值