介绍
默认情况下,建立的套接字都是阻塞的,程序会停在等待网络事件的地方(accept),直到网络io条件满足,才会继续向下执行
代码实现
#include <WinSock2.h>
#include <Windows.h>
#include <WS2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT 27015
int __cdecl main(int argc,TCHAR* argv[]) {
WSADATA wsaData;
int iResult;
SOCKET ServerSocket = INVALID_SOCKET;
SOCKET AcceptSocket = INVALID_SOCKET;
char recvbuf[DEFAULT_BUFLEN];
int recvBufLen = DEFAULT_BUFLEN;
sockaddr_in addrClient;
int addrClinetLen = sizeof(sockaddr_in);
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult!=0)
{
printf_s("wsatartup faild with error code %d\n", iResult);
return 1;
}
ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (ServerSocket==INVALID_SOCKET)
{
printf_s("SOCKET FAILED WITH ERROR CODE %d",WSAGetLastError());
WSACleanup();
return 1;
}
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(DEFAULT_PORT);
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
iResult = bind(ServerSocket,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN));
if (iResult==SOCKET_ERROR)
{
printf_s("bind falied with error code %d\n",iResult);
closesocket(ServerSocket);
WSACleanup();
return 1;
}
iResult = listen(ServerSocket,SOMAXCONN);
if (iResult==SOCKET_ERROR)
{
printf_s("listen failed with error code %d",iResult);
closesocket(ServerSocket);
WSACleanup();
return -1;
}
printf_s("TCP server starting");
int err;
while (true)
{
AcceptSocket = accept(ServerSocket, (sockaddr FAR*) & addrClient, &addrClinetLen);
if (AcceptSocket == INVALID_SOCKET)
{
printf_s("accetp failed \n");
closesocket(ServerSocket);
WSACleanup();
return 1;
}
while (true)
{
memset(recvbuf, 0, recvBufLen);
iResult = recv(AcceptSocket, recvbuf, recvBufLen, 0);
if (iResult>0)
{
printf_s("recv data %d byte\n",iResult);
int iSendResult = send(AcceptSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(AcceptSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
continue;
}
else if (iResult == 0)
{
printf_s("conn closeing ....\n");
closesocket(AcceptSocket);
break;
}
else
{
printf_s("%d",iResult);
printf_s("recv failed with error%d\n",WSAGetLastError());
closesocket(AcceptSocket);
closesocket(ServerSocket);
WSACleanup();
return 1;
}
}
}
closesocket(ServerSocket);
closesocket(AcceptSocket);
WSACleanup();
return 0;
}
评价
- 优点:使用非常简单直接
- 缺点:
- 无法同时处理多个套接字
- 程序会在等待io处卡死,程序效率低下
改进思路:
- 多线程并发处理多个io,即一个线程处理一个socket,
- 问题:线程频繁创建,唤醒,睡眠。导致用户态内核态频繁切换。增大系统开销
- 线程同步,条件竞争,需要研究锁问题
- 异步,非阻塞处理多个io
- 这种情况下,程序仍然为单线程,但是对io处理上使用回调机制,捕获io条件满足时机达到一对多效果
- 问题:确定网络事件发生、网络io消息,回调机制