1. 程式人生 > >服務端用非阻塞socket客戶端用阻塞socket

服務端用非阻塞socket客戶端用阻塞socket

       之前, 我們簡要第瞭解了一下非阻塞的socket。 在本文中, 我們讓服務端用非阻塞socket, 客戶端依然用我們熟悉的阻塞的socket.

       服務端程式如下(非阻塞的socket):

#include <stdio.h>
#include <winsock2.h>   
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")   

int main()
{
	// 網路初始化
	WSADATA wsd;   
    WSAStartup(MAKEWORD(2,2), &wsd);


	// 預設為阻塞socket
    SOCKET sServer = socket(AF_INET,SOCK_STREAM, 0);    
   

	// 設定為非阻塞socket
	int iMode = 1;
	ioctlsocket(sServer, FIONBIO, (u_long FAR*)&iMode);


    // 設定伺服器套接字地址   
    SOCKADDR_IN addrServ;   
    addrServ.sin_family = AF_INET;   
    addrServ.sin_port = htons(8888);
    addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);    
    bind(sServer,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN));   
   

	// 用耳朵聽聽
    listen(sServer, 5);   
    

    // 接受客戶請求 
	printf("accept\n");
    sockaddr_in addrClient;
    int len = sizeof(addrClient);   
	SOCKET sClient = 0; 
	while(1)
	{
		sClient = accept(sServer,(sockaddr FAR*)&addrClient, &len);   
		if(INVALID_SOCKET == sClient)   
		{   
			int err = WSAGetLastError();
			if(WSAEWOULDBLOCK == err)  // 沒有客戶端來connect
			{
				Sleep(100);
				continue;
			}

			// 其實這裡還應該考慮一下異常比較好
		} 

		printf("accept ok\n");
		break;
	}

	int iRet = -1;
	while(1)
	{
		char szRecvBuf[100] = {0};
		iRet = recv(sClient, szRecvBuf, sizeof(szRecvBuf), 0);
		if(SOCKET_ERROR == iRet)   
		{   
			int err = WSAGetLastError();
			if(WSAEWOULDBLOCK == err) // 接收socket對應的核心緩衝區中暫時沒有資料
			{
				Sleep(100);
				continue;
			}

			// 這裡考慮一下異常比較好
		}  
		
		printf("%s\n", szRecvBuf);
		break;
	}


	// 網路釋放
	closesocket(sServer);   
    closesocket(sClient);   
    WSACleanup();  
	return 0;
}
      執行程式, 開啟服務端程序。

      下面, 我們看看客戶端的程式(阻塞的socket):

#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")

int main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	wVersionRequested = MAKEWORD(2, 2);
	
	WSAStartup( wVersionRequested, &wsaData );

	SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 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(8888);
	connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));

	send(sockClient, "hello world", strlen("hello world") + 1, 0);

	closesocket(sockClient);
	WSACleanup();

	return 0;
}
      執行該程式。

      服務端程序列印的結果為:

accept
accept ok
hello world

      最後, 根據實踐的結果, 我不得不在這裡強調一下: 服務端的recv函式是否阻塞, 並不取決於客戶端的sockClient是否是阻塞式的, 而是取決於服務端的sServer是否為阻塞式的, 所以, 上面服務端的recv並不會阻塞。

      好, 本文我們就先學到這裡。