区别:
阻塞式迭代模式:
每次只服务一个连接,只有在服务完当前服务器连接之后,才会继续服务下一个客户端连接
阻塞式并发连接模式:
通过多线程,可以同时服务多个连接,每一个线程处理一个客户端连接
步骤:
阻塞式迭代模式步骤:
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;
}