Socket阻塞模式开发

xiaoxiao2021-02-28  139

Windows Sockets在阻塞和非阻塞两种模式下执行I/O操作,其中,以socket()、WSASocket()函数创建的套接字默认都是阻塞套接字。在阻塞模式下,在I/O操作完成前,执行的操作函数将一直等候而不会立即返回,该函数所在的线程会阻塞在这里。相反,在非阻塞模式下,套接字函数会立即返回,而不管I/O操作是否完成,该函数所在的线程会继续运行。

例如,在调用recv函数时,发生在内核中等待数据和复制数据的过程如图:

调用recv时,系统首先检查是否有准备好的数据,如果数据没有准备好,系统就处于等待状态。当数据准备好后,将数据从系统缓冲区复制到用户空间,然后该函数返回。在套接字应用程序中,当调用recv时,用户空间不一定就已经存在数据,此时,recv函数就会处于等待状态。

但是,并不是所有的windows sockets API以阻塞套接字为参数调用都会发生阻塞,例如,以阻塞套接字为参数调用bind()、listen()时,都会立即返回。Windows sockets API中可能阻塞套接字的API:

1、输入操作

recv()、recvfrom()、WSARecv()、WSARecvfrom()。以阻塞套接字为参数调用时,如果此时套接字缓冲区没有数据可读,则调用线程在数据到来前一直睡眠。

2、输出操作

send()、sendto()、WSASend()、WSASendto()。以阻塞套接字为参数调用时,如果此时套接字缓冲区没有可用空间,则调用线程在有空间前前一直睡眠。

3、接受连接

accept()、WSAAccept()。以阻塞套接字为参数调用时,将等待对方的连接请求,如果此时没有连接请求,线程会一直睡眠直到连接请求到来。

4、连接请求

connect()、WSAConnect()。对于TCP连接,客户端以阻塞套接字为参数,调用这些函数向服务器发起连接,在收到服务器的应答前,该函数不会反回。这意味着TCP连接总会等待至少从客户端到服务器的一次往返时间。

例:客户端和服务器端的相互问候

服务器代码:

#include "stdafx.h" #include<iostream> #include<Winsock2.h> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { WORD wVersionRequested; int err; WSADATA wsaData; wVersionRequested=MAKEWORD(1,1); err=WSAStartup(wVersionRequested,&wsaData); if(err!=0) { return 0; } SOCKET sockSrv=socket(AF_INET,SOCK_DGRAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(3242); bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); char recvBuf[100]; char sendBuf[100]; char tempBuf[200]; SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); while(1) { recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len); if((recvBuf[0]=='q')&&(strlen(recvBuf)==1)) { sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len); cout<<"chat end!"<<endl; break; } sprintf(tempBuf,"%s : %s","Client",recvBuf); cout<<tempBuf<<endl; cout<<"input:"<<endl; cin.getline(sendBuf,100); sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,sizeof(SOCKADDR)); } closesocket(sockSrv); WSACleanup(); cin.get(); return 0; } 客户端代码:

#include "stdafx.h" #include<iostream> #include<Winsock2.h> #include<string> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { WORD wVersionRequested; int err; WSADATA wsaData; wVersionRequested=MAKEWORD(1,1); err=WSAStartup(wVersionRequested,&wsaData); if(0!=err) { return 0; } SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(3242); int len=sizeof(SOCKADDR); char recvBuf[100]; char sendBuf[100]; char tempBuf[200]; while(1) { cout<<"input:"<<endl; cin.getline(sendBuf,100); sendto(sockClient,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrSrv,len); recvfrom(sockClient,recvBuf,100,0,(SOCKADDR*)&addrSrv,&len); if((recvBuf[0]=='q')&&(strlen(recvBuf)==1)) { sendto(sockClient,"q",sizeof("q")+1,0,(SOCKADDR*)&addrSrv,len); cout<<"chat end!"<<endl; break; } sprintf(tempBuf,"%s: %s","Srv",recvBuf); cout<<tempBuf<<endl; } closesocket(sockClient); WSACleanup(); cin.get(); return 0; }

阻塞模式套接字的优势和不足:

优势:使用阻塞套接字开发网络程序比较简单,容易实现。当希望能够立即发送和接受数据,且处理的套接字数量比较少的情况下,使用阻塞模式开发比较合适

不足:在大量建好的套接字线程之间通信比较困难。当希望同时处理大量套接字时,将无从下手,扩展性差。

转载请注明原文地址: https://www.6miu.com/read-81577.html

最新回复(0)