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

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