Windows網絡編程 阻塞式迭代模式和併發模式

區別:

阻塞式迭代模式:

每次只服務一個連接,只有在服務完當前服務器連接之後,纔會繼續服務下一個客戶端連接

阻塞式併發連接模式:

通過多線程,可以同時服務多個連接,每一個線程處理一個客戶端連接

 

步驟:

阻塞式迭代模式步驟:

1,先連接處理,綁定本地地址和監聽

2,接受一個客戶端連接並返回對應的連接的套接字

3,處理一個客戶端的連接,實現接受和發送數據

4,關閉一個服務

5,服務器主體

阻塞式併發模式:

和迭代模式基本相同,只是在於處理客戶端連接上,我們需要用到多線程來處理客戶端連接,以給予服務端同時處理業務的能力

多線程函數:

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,      // pointer to security attributes
  DWORD dwStackSize,                  // initial thread stack size
  LPTHREAD_START_ROUTINE lpStartAddress,       // pointer to thread function
  LPVOID lpParameter,                   // argument for new thread
  DWORD dwCreationFlags,                // creation flags
  LPDWORD lpThreadId                  // pointer to receive thread ID
);

第一個參數是指向SECURITY_ATTRIBUTES型態的結構的指針。一般取值0
第二個參數是用於新線程的初始堆棧大小,默認值爲0。在任何情況下,Windows根據需要動態延長堆棧的大小。
第三個參數是指向線程函數的指標。函數名稱沒有限制,但是必須以下列形式聲明:
DWORD WINAPI ThreadProc (PVOID pParam) ;
第四個參數爲傳遞給ThreadProc的參數。這樣主線程和從屬線程就可以共享數據。
第五個參數通常爲0,但當建立的線程不馬上執行時爲旗標CREATE_SUSPENDED。線程將暫停直到呼叫ResumeThread來恢復線程的執行爲止。
第六個參數是一個指標,指向接受執行緒ID值的變量。

 

代碼:

迭代模型代碼:

// 阻塞式迭代模型.cpp : 定義控制檯應用程序的入口點。

#include "stdafx.h"

#include<winsock2.h>
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

#define nSERPort 8000
#define nBufMaxSize 1024

//封裝的打印
void debugLog(char *logStr)
{
    cout << logStr << WSAGetLastError() << endl;
}

//初始化Socket
BOOL InitSocket()
{
    WSAData wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData))
    {
        debugLog("InitSocket -> WSAStartup error");
        return FALSE;
    }
}

//先創建套接字 綁定本地地址 然後開始監聽
SOCKET Bind_Listen(int nBacklog)
{
    SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (hSocket == INVALID_SOCKET)
    {
        debugLog("Bind_Listen -> socket error!");
        return INVALID_SOCKET;
    }

    sockaddr_in saSerAddr;
    saSerAddr.sin_family = AF_INET;
    saSerAddr.sin_addr.s_addr = htonl(ADDR_ANY);
    saSerAddr.sin_port = htons(nSERPort);

    if (bind(hSocket, (LPSOCKADDR)&saSerAddr, sizeof(saSerAddr)))
    {
        debugLog("Bind_Listen -> bind error");
        closesocket(hSocket);
        return INVALID_SOCKET;
    }
    if (listen(hSocket, nBacklog) == SOCKET_ERROR)
    {
        closesocket(hSocket);
        debugLog("Bind_Listen -> listen error");
        return INVALID_SOCKET;
    }
    return hSocket;
}

//接受一個客戶端連接並返回對應的連接的套接字
SOCKET AcceptConnetion(SOCKET hScoket)
{
    sockaddr_in saConAddr;

    int nSize = sizeof(saConAddr);
    SOCKET sd = accept(hScoket, (LPSOCKADDR)&saConAddr, &nSize);
    if (sd == INVALID_SOCKET)
    {
        debugLog("AcceptConnetion -> connect error");
        return INVALID_SOCKET;
    }
    return sd;
}

//處理一個客戶端的連接,實現接受和發送數據
BOOL ClientConFun(SOCKET sd)
{
    char Buf[nBufMaxSize];
    int nRetByte;
    //循環處理數據
    do
    {
        //接受到來自客戶端的數據
        nRetByte = recv(sd, Buf, nBufMaxSize, 0);
        if (nRetByte == SOCKET_ERROR)
        {
            debugLog("ClientConFun -> recv error!");
            return FALSE;
        }
        else if (nRetByte != 0)
        {
            Buf[nRetByte] = 0;
            cout << "接收到一條數據:" << Buf << endl;
            int nSend = 0;
            while (nSend < nRetByte)
            {
                //把接收到的數據回發過去
                int nTemp = send(sd, &Buf[nSend], nRetByte - nSend, 0);
                if (nTemp>0)
                {
                    nSend += nTemp;
                }
                else if (nTemp == SOCKET_ERROR)
                {
                    debugLog("ClientConFun -> send error");
                    return FALSE;
                }
                else
                {
                    //send 返回0由於此時send<nretByte 也就是說
                    //數據還沒有發送出去,表示客戶端被意外關閉了
                    debugLog("ClientConFun -> send ->close error");
                    return FALSE;
                }
            }
        }
    } while (nRetByte != 0);

    return TRUE;
}

//關閉一個連接
BOOL CloseConnect(SOCKET sd)
{
    //首先發送一個TCP FIN分段,向對方表明已經完成數據發送
    if (shutdown(sd, SD_SEND) == SOCKET_ERROR)
    {
        debugLog("CloseConnect -> shutdown error");
        return FALSE;
    }

    char Buf[nBufMaxSize];
    int nRetByte;

    do
    {
        nRetByte = recv(sd, Buf, nBufMaxSize, 0);
        if (nRetByte == SOCKET_ERROR)
        {
            debugLog("CloseConnect ->recv error");
            break;
        }
        else if (nRetByte > 0)
        {
            debugLog("CloseConnect 錯誤的接收數據");
            break;
        }
    } while (nRetByte != 0);

    if (closesocket(sd) == SOCKET_ERROR)
    {
        debugLog("CloseConnect ->closeSocket error");
        return FALSE;
    }
    return TRUE;
}

//服務器主體
void MyTcpSerFun()
{
    SOCKET hSocket = Bind_Listen(1);
    if (hSocket == INVALID_SOCKET)
    {
        debugLog("MyTcpSocket -> Bind_Listen error");
        return;
    }
    while (TRUE)
    {
        //返回客戶端的套接字
        SOCKET sd = AcceptConnetion(hSocket);
        if (sd == INVALID_SOCKET)
        {
            debugLog("MyTcpSerFun ->AcceptConnection error");
            break;
        }

        //客戶端處理
        if (ClientConFun(sd) == FALSE)
        {
            //break;
        }

        //關閉一個客戶端的連接
        if (CloseConnect(sd) == FALSE)
        {
            break;
        }
    }

    if (closesocket(hSocket) == SOCKET_ERROR)
    {
        debugLog("MyTcpSerFun -> closesocket error");
        return;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    //初始化
    InitSocket();
    //業務數據處理
    MyTcpSerFun();
    //釋放WinSocket
    WSACleanup();
    system("pause");
    return 0;
}

 

 

併發模型代碼:

// 阻塞式併發模型.cpp : 定義控制檯應用程序的入口點。

#include "stdafx.h"

#include<winsock2.h>
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

#define nSERPort 8000
#define nBufMaxSize 1024

//封裝的打印
void debugLog(char *logStr)
{
    cout << logStr << WSAGetLastError() << endl;
}

//初始化Socket
BOOL InitSocket()
{
    WSAData wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData))
    {
        debugLog("InitSocket -> WSAStartup error");
        return FALSE;
    }
}

//先創建套接字 綁定本地地址 然後開始監聽
SOCKET Bind_Listen(int nBacklog)
{
    SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (hSocket == INVALID_SOCKET)
    {
        debugLog("Bind_Listen -> socket error!");
        return INVALID_SOCKET;
    }

    sockaddr_in saSerAddr;
    saSerAddr.sin_family = AF_INET;
    saSerAddr.sin_addr.s_addr = htonl(ADDR_ANY);
    saSerAddr.sin_port = htons(nSERPort);

    if (bind(hSocket, (LPSOCKADDR)&saSerAddr, sizeof(saSerAddr)))
    {
        debugLog("Bind_Listen -> bind error");
        closesocket(hSocket);
        return INVALID_SOCKET;
    }
    if (listen(hSocket, nBacklog) == SOCKET_ERROR)
    {
        closesocket(hSocket);
        debugLog("Bind_Listen -> listen error");
        return INVALID_SOCKET;
    }
    return hSocket;
}

//接受一個客戶端連接並返回對應的連接的套接字
SOCKET AcceptConnetion(SOCKET hScoket)
{
    sockaddr_in saConAddr;

    int nSize = sizeof(saConAddr);
    SOCKET sd = accept(hScoket, (LPSOCKADDR)&saConAddr, &nSize);
    if (sd == INVALID_SOCKET)
    {
        debugLog("AcceptConnetion -> connect error");
        return INVALID_SOCKET;
    }
    return sd;
}

//處理一個客戶端的連接,實現接受和發送數據
BOOL ClientConFun(SOCKET sd)
{
    char Buf[nBufMaxSize];
    int nRetByte;
    //循環處理數據
    do
    {
        //接受到來自客戶端的數據
        nRetByte = recv(sd, Buf, nBufMaxSize, 0);
        if (nRetByte == SOCKET_ERROR)
        {
            debugLog("ClientConFun -> recv error!");
            return FALSE;
        }
        else if (nRetByte != 0)
        {
            Buf[nRetByte] = 0;
            cout << "接收到一條數據:" << Buf << endl;
            int nSend = 0;
            while (nSend < nRetByte)
            {
                //把接收到的數據回發過去
                int nTemp = send(sd, &Buf[nSend], nRetByte - nSend, 0);
                if (nTemp>0)
                {
                    nSend += nTemp;
                }
                else if (nTemp == SOCKET_ERROR)
                {
                    debugLog("ClientConFun -> send error");
                    return FALSE;
                }
                else
                {
                    //send 返回0由於此時send<nretByte 也就是說
                    //數據還沒有發送出去,表示客戶端被意外關閉了
                    debugLog("ClientConFun -> send ->close error");
                    return FALSE;
                }
            }
        }
    } while (nRetByte != 0);

    return TRUE;
}

//關閉一個連接
BOOL CloseConnect(SOCKET sd)
{
    //首先發送一個TCP FIN分段,向對方表明已經完成數據發送
    if (shutdown(sd, SD_SEND) == SOCKET_ERROR)
    {
        debugLog("CloseConnect -> shutdown error");
        return FALSE;
    }

    char Buf[nBufMaxSize];
    int nRetByte;

    do
    {
        nRetByte = recv(sd, Buf, nBufMaxSize, 0);
        if (nRetByte == SOCKET_ERROR)
        {
            debugLog("CloseConnect ->recv error");
            break;
        }
        else if (nRetByte > 0)
        {
            debugLog("CloseConnect 錯誤的接收數據");
            break;
        }
    } while (nRetByte != 0);

    if (closesocket(sd) == SOCKET_ERROR)
    {
        debugLog("CloseConnect ->closeSocket error");
        return FALSE;
    }
    return TRUE;
}

//線程處理業務
DWORD WINAPI ClientThreadFun(LPVOID lpParam)
{
    SOCKET sd = (SOCKET)lpParam;
    //客戶端處理
    if (ClientConFun(sd) == FALSE)
    {
        //break;
    }

    //關閉一個客戶端的連接
    if (CloseConnect(sd) == FALSE)
    {
        //break;
    }
    return 0;
}

//服務器主體
void MyTcpSerFun()
{
    SOCKET hSocket = Bind_Listen(1);
    if (hSocket == INVALID_SOCKET)
    {
        debugLog("MyTcpSocket -> Bind_Listen error");
        return;
    }
    while (TRUE)
    {
        //返回客戶端的套接字
        SOCKET sd = AcceptConnetion(hSocket);
        if (sd == INVALID_SOCKET)
        {
            debugLog("MyTcpSerFun ->AcceptConnection error");
            break;
        }

        //當接受到客戶端的請求連接,我們就爲他開一個線程
        DWORD dwThreadId;
        HANDLE hThread = CreateThread(0, 0, ClientThreadFun, (LPVOID)sd, 0, &dwThreadId);
        if (hThread)
        {
            CloseHandle(hThread);
        }

#if 0
        //客戶端處理
        if (ClientConFun(sd) == FALSE)
        {
            //break;
        }

        //關閉一個客戶端的連接
        if (CloseConnect(sd) == FALSE)
        {
            break;
        }
#endif
    }

    if (closesocket(hSocket) == SOCKET_ERROR)
    {
        debugLog("MyTcpSerFun -> closesocket error");
        return;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    //初始化
    InitSocket();
    //業務數據處理
    MyTcpSerFun();
    //釋放WinSocket
    WSACleanup();
    system("pause");
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章