• TCP阻塞模式开发


    在阻塞模式下,在IO操作完成前,执行的操作函数将一直等候而不会立刻返回,该函数所在的进程会阻塞在这里。相反,在非阻塞模式下,套接字函数会立即返回,而不管IO是否完成,该函数所在的线程将继续运行。阻塞模式编程简单,但效率低;非阻塞模式编程复杂,但效率高,比如:

    举个简单的例子,你点击一个发送按钮:
    如果是阻塞式的,那么在发送未完成之前,界面就会"卡死"。
    而非阻塞式的,无论数据有没有完成,你都继续进行界面的操作


    server:

    // Server.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <iostream>
    #include <WINSOCK2.H>
    #pragma comment(lib, "wsock32.lib")
    
    using namespace std;
    
    #define SERVER_EXIT_OK				0	//服务器正常退出
    #define SERVER_DLL_REEOR			1	//调用Windows sockets DLL失败
    #define SERVER_API_ERROR			2	//调用Windows sockets API失败
    #define	SERVERPORT					5555//服务器TCP端口
    #define MAX_NUM_BUF					64	//缓冲区最大尺寸
    
    //变量
    char	bufRecv[MAX_NUM_BUF];			//读缓冲区
    char	bufSend[MAX_NUM_BUF];			//写缓冲区
    SOCKET	sServer;						//服务器监听套接字
    SOCKET	sClient;						//接受客户端套接字
    BOOL	bConning;						//与客户端的连接状态
    
    //函数
    void	InitMember(void);				//初始化成员变量 
    int		ExitClient(int nExit);			//客户端退出
    BOOL	RecvLine(SOCKET s, char* buf);	//读取一行数据
    BOOL	SendLine(SOCKET s, char* buf);	//发送一行数据
    int		HandleSocketError(char *str);	//对Windows sockets API调用错误处理
    void	ShowSocketMsg(char* str);		//显示错误信息
    
    //主函数
    int main(int argc, char* argv[])
    {
    
    	InitMember();					//初始化变量
    	
    	WORD	wVersionRequested;		//应用程序需要Windows sockets DLL的版本
    	WSADATA	wsaData;				//Windows sockets DLL版本信息
    	int		retVal;					//调用Windows sockets API返回值		
    	//初始化Windows Sockets DLL
    	wVersionRequested = MAKEWORD(1,1);
    	retVal = WSAStartup(wVersionRequested, &wsaData);
    	if ( 0 != retVal ) 
    	{
    		ShowSocketMsg("Can not find a usable Windows Sockets dll!");
    		return SERVER_DLL_REEOR;
    	}	
    	//确保WinSock DLL支持1.1
    	if ( LOBYTE( wsaData.wVersion ) != 1 ||	HIBYTE( wsaData.wVersion ) != 1)
    	{
    		ShowSocketMsg("Can not find a usable Windows Sockets dll!");
    		WSACleanup( );
    		return SERVER_DLL_REEOR; 
    	}
    	
    	
    	//创建套接字
    	sServer= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	
    	if(INVALID_SOCKET == sServer)
    	{
    		return HandleSocketError("Failed socket()!");
    	}
    	
    	//服务器套接字地址 
    	SOCKADDR_IN addrServ;
    	addrServ.sin_family = AF_INET;
    	addrServ.sin_port = htons(SERVERPORT);
    	addrServ.sin_addr.s_addr = INADDR_ANY;		
    	//绑定套接字
    	retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
    	if(SOCKET_ERROR == retVal)
    	{
    		closesocket(sServer);						//关闭套接字
    		return HandleSocketError("Failed bind()!");	//错误处理
    	}
    	
    	//开始监听 
    	retVal = listen(sServer, 1);
    	if(SOCKET_ERROR == retVal)
    	{
    		closesocket(sServer);						//关闭套接字
    		return HandleSocketError("Failed listen()!");//错误处理
    	}
    	
    
    	//等待客户端的连接	
    	cout << "Server succeeded!" << endl;
    	cout << "Waiting for new clients..." << endl;
    
    
    
    	//接受客户端请求
    	sockaddr_in addrClient;
    	int addrClientlen = sizeof(addrClient);
    	sClient = accept(sServer,(sockaddr FAR*)&addrClient, &addrClientlen);
    	if(INVALID_SOCKET == sClient)
    	{
    		closesocket(sServer);							//关闭套接字
    		return HandleSocketError("Failed accept()!");	//错误处理
    	}else{
    		bConning = TRUE;								//客户端请求成功
    	}
    	
    	//显示客户端的IP和端口
    	char *pClientIP = inet_ntoa(addrClient.sin_addr);
    	u_short  clientPort = ntohs(addrClient.sin_port);	
    	cout<<"Accept a client."<<endl;
    	cout<<"IP: "<<pClientIP<<endl;
    	cout<<"Port: "<<clientPort<<endl;
    
    
    	//接收客户端数据
    	if (!RecvLine(sClient, bufRecv))
    	{
    		return	ExitClient(SERVER_API_ERROR);//退出
    	}	
    	//显示客户端数据
    	cout << bufRecv<<endl;
    
    
    	//向客户端发送数据
    	strcpy(bufSend, "Hello,Client!
    ");
    	if (!SendLine(sClient, bufSend))
    	{
    		return	ExitClient(SERVER_API_ERROR);
    	}
    	
    
    	//显示退出信息
    	cout << "Server exiting..." << endl;
    	
    	//退出
    	return ExitClient(SERVER_EXIT_OK);
    }
    
    
    
    /*
     *	初始化成员变量
     */
    void	InitMember(void)
    {
    	//初始化读和写缓冲区
    	memset(bufRecv, 0, MAX_NUM_BUF);
    	memset(bufSend, 0, MAX_NUM_BUF);
    
    	//初始化
    	sServer = INVALID_SOCKET;
    	sClient = INVALID_SOCKET;
    
    	//没有连接状态
    	bConning = FALSE;
    }
    
    
    /*
     *	退出
     */
    int		ExitClient(int nExit)
    {
    	closesocket(sServer);	//关闭监听套接字
    	closesocket(sClient);	//关闭连接客户端套接接
    	WSACleanup();			//卸载Windows sockets DLL 清理内存
    	return nExit;			//退出
    }
    /*
     *	读一行数据
     */
    BOOL	RecvLine(SOCKET s, char* buf)
    {
    	BOOL	retVal = TRUE;			//返回值
    	BOOL	bLineEnd = FALSE;		//行结束
    	int		nReadLen = 0;			//读入字节数
    	int		nDataLen = 0;			//数据长度
    	while (!bLineEnd && bConning)	//与客户端连接 没有换行
    	{
    		nReadLen = recv(s, buf + nDataLen, 1, 0);//每次接收一个字节
    		
    		//错误处理
    		if (SOCKET_ERROR == nReadLen)
    		{
    			int nErrCode = WSAGetLastError();//错误代码
    			if (WSAENOTCONN == nErrCode)
    			{
    				ShowSocketMsg("The socket is not connected!");
    				
    			}else if(WSAESHUTDOWN == nErrCode)
    			{
    				ShowSocketMsg("The socket has been shut down!");
    				
    			}else if (WSAETIMEDOUT == nErrCode)
    			{
    				ShowSocketMsg("The connection has been dropped!");							
    			}else if (WSAECONNRESET == nErrCode)
    			{
    				ShowSocketMsg("The virtual circuit was reset by the remote side!");
    			}else{}	
    			
    			retVal = FALSE;	//读数据失败
    			break;			//跳出循环						
    		}
    		
    		
    		if (0 == nReadLen)//客户端关闭
    		{
    			retVal = FALSE;	//读数据失败
    			break ;			//跳出循环			
    		}
    		
    		//读入数据
    		if ('
    ' == *(buf + nDataLen))	//换行符
    		{
    			bLineEnd = TRUE;			//接收数据结束
    		}else{
    			nDataLen += nReadLen;		//增加数据长度
    		}	
    	}
    	
    	return retVal;
    }
    
    /*
     *	//发送一行数据
     */
    BOOL	SendLine(SOCKET s, char* str)
    {
    	int retVal;//返回值
    	retVal = send(s, str, strlen(str), 0);//一次发送
    
    	//错误处理
    	if (SOCKET_ERROR == retVal)
    	{
    		int nErrCode = WSAGetLastError();//错误代码
    		if (WSAENOTCONN == nErrCode)
    		{
    			ShowSocketMsg("The socket is not connected!");
    			
    		}else if(WSAESHUTDOWN == nErrCode)
    		{
    			ShowSocketMsg("The socket has been shut down!");
    			
    		}else if (WSAETIMEDOUT == nErrCode)
    		{
    			ShowSocketMsg("The connection has been dropped!");
    		}else{}	
    		
    		return FALSE;	//发送失败
    	}
    	
    	return TRUE;		//发送成功
    }
    	
    /*
     *	错误处理
     */
    int		HandleSocketError(char *str)
    {
    	ShowSocketMsg(str);		//显示错误消息	
    	WSACleanup();			//卸载Windows socket DLL	
    	return SERVER_API_ERROR;//退出应用程序
    }
    
    /*
     *	显示错误
     */
    void	ShowSocketMsg(char* str)
    {
    	MessageBox(NULL, str, "SERVER ERROR", MB_OK);
    }
    
    	

    client:

    #include "stdafx.h"
    
    #include <windows.h>
    #include <winsock.h>
    #include <iostream>
    #pragma comment(lib, "wsock32.lib")
    
    using namespace std;
    
    #define CLIENT_EXIT_OK				0	//客户端正常退出
    #define CLIENT_DLL_REEOR			1	//调用Windows socket dll失败
    #define CLIENT_API_ERROR			2	//调用Windows socket api失败
    #define MAX_NUM_BUF					64	//缓冲区的最大长度
    #define	SERVERPORT					5555//服务器TCP端口
    
    
    //变量
    char	bufRecv[MAX_NUM_BUF];			//读缓冲区
    char	bufSend[MAX_NUM_BUF];			//写缓冲区
    SOCKET	sHost;							//socket
    BOOL	bConning;						//连接服务器状态
    
    //函数
    void	InitMember(void);				//初始化变量
    int		ExitClient(int nExit);			//退出
    BOOL	RecvLine(SOCKET s, char* buf);	//读取一行数据
    void	ShowErrorMsg(void);				//显示错误信息
    
    //主函数
    int main()
    {
    
    	//初始化变量
    	InitMember();
    
    	WORD	wVersionRequested;		//应用程序需要Windows sockets DLL的版本
    	WSADATA	wsaData;				//Windows sockets DLL版本信息
    	int		retVal;					//调用Windows sockets API返回值
    
    	//初始化Windows Sockets DLL
    	wVersionRequested = MAKEWORD(1,1);	
    	retVal = WSAStartup(wVersionRequested,(LPWSADATA)&wsaData);
    	if ( 0 != retVal ) 
    	{
    		MessageBox(NULL, "Can not find a usable Windows Sockets dll!", "ERROR", MB_OK);
    		return CLIENT_DLL_REEOR;
    	}
    
    
    	//创建Windows socket
    	sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	if(INVALID_SOCKET == sHost)
    	{
    		ShowErrorMsg();			//显示错误信息
    		WSACleanup();			//释放资源
    		return CLIENT_API_ERROR;//退出
    	}
    
    	//准备连接服务器
    	cout << "Client succeeded!" << endl;
    	cout<<"Be ready to connect to server..."<<endl;
    
    	
    	
    	//获取主机的信息
    	LPHOSTENT hostEntry;
    	char hostname[MAX_NUM_BUF];
    	gethostname(hostname,MAX_NUM_BUF);			//获取主机名称
    	hostEntry = gethostbyname(hostname);		//获取主机信息
    	if(!hostEntry)
    	{
    		ShowErrorMsg();							//显示错误信息
    		return ExitClient(CLIENT_API_ERROR);	//退出
    	}
    	//设置sockaddr_in
    	SOCKADDR_IN addrServ;
    	addrServ.sin_family = AF_INET;
    	addrServ.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
    	addrServ.sin_port = htons(SERVERPORT);
    	//连接服务器
    	retVal=connect(sHost,(LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
    	if(SOCKET_ERROR == retVal)
    	{
    		ShowErrorMsg();							//显示错误信息
    		return ExitClient(CLIENT_API_ERROR);	//退出
    	}else{
    		bConning = TRUE;						//连接服务器成功
    	}     
    	//连接服务器成功
    	cout<<"Connect successfully!"<<endl;
    
    
    	//向服务器发送数据
    	strcpy(bufSend, "Hello, Server!
    ");
    	retVal = send(sHost, bufSend, strlen(bufSend), 0);
    	if (SOCKET_ERROR == retVal)
    	{
    		ShowErrorMsg();							//显示错误信息
    		return ExitClient(CLIENT_API_ERROR);	//退出
    	}
    
    	//从服务器接收数据
    	if (!RecvLine(sHost, bufRecv))
    	{
    		ShowErrorMsg();							//显示错误信息
    		return ExitClient(CLIENT_API_ERROR);	//退出
    	}
    	//显示服务器的应答
    	cout<<bufRecv<<endl;
    
    	//退出
    	return ExitClient(CLIENT_EXIT_OK);
    }
    
    
    /*
     *	显示错误信息
     */
    void	ShowErrorMsg(void)
    {
    	int nErrCode = WSAGetLastError();//获取错误代码
    
    	HLOCAL hlocal = NULL;  
    	
    	//获取错误的文本字符串
    	BOOL fOk = FormatMessage(
    		FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
    		NULL, nErrCode, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
    		(PTSTR)&hlocal, 0, NULL);
    	
    	//显示错误信息
    	if (hlocal != NULL)
    	{
    		MessageBox(NULL, (char*)LocalLock(hlocal), "CLIENT ERROR", MB_OK);	
    		LocalFree(hlocal);
    	}
    }
    
    
    /*
     *	初始化成员变量
     */
    void	InitMember(void)
    {
    	//初始化读和写缓冲区
    	memset(bufRecv, 0, MAX_NUM_BUF);
    	memset(bufSend, 0, MAX_NUM_BUF);
    	//初始化
    	sHost = INVALID_SOCKET;
    	//没有连接状态
    	bConning = FALSE;
    }
    
    /*
     *	退出
     */
    int		ExitClient(int nExit)
    {
    	closesocket(sHost);		//关闭套接字
    	WSACleanup();			//卸载Windows sockets DLL 清理内存
    
    		//显示退出信息
    	cout << "Client exiting..." << endl;
    	Sleep(20000);
    	return nExit;	//退出
    }
    
    
    /*
     *	读取一行数据
     */
    BOOL	RecvLine(SOCKET s, char* buf)
    {
    	BOOL	retVal = TRUE;			//返回值
    	BOOL	bLineEnd = FALSE;		//行结束
    	int		nReadLen = 0;			//读入字节数
    	int		nDataLen = 0;			//数据长度
    	while (!bLineEnd && bConning)	//与客户端连接 没有换行
    	{
    		nReadLen = recv(s, buf + nDataLen, 1, 0);//每次接收一个字节		
    		//错误处理
    		if (SOCKET_ERROR == nReadLen)
    		{			
    			retVal= FALSE;	//读数据失败
    			break;			//跳出循环						
    		}		
    		
    		if (0 == nReadLen)//客户端关闭
    		{
    			retVal = FALSE;	//读数据失败
    			break ;			//跳出循环			
    		}
    		
    		//读入数据
    		if ('
    ' == *(buf + nDataLen))	//换行符
    		{
    			bLineEnd = TRUE;			//接收数据结束
    		}else{
    			nDataLen += nReadLen;		//增加数据长度
    		}	
    	}
    	
    	return retVal;
    }


    
  • 相关阅读:
    MySql中启用InnoDB数据引擎的方法
    云说的到底对不对,京东到底行不行?
    hibernate HQL查询的参数绑定
    MySQL到底能支持多大的数据量?
    C# RSA和Java RSA互通
    Log4j 2使用教程
    Log4j.properties配置详解
    JMX 基础Demo
    iBatis缓存实现源码分析-FIFO,LUR实现方法
    SqlMapClient 创建过程之SqlMapConfigParser源码走读
  • 原文地址:https://www.cnblogs.com/ggzone/p/10121333.html
Copyright © 2020-2023  润新知