在阻塞模式下,在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!\n");
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 ('\n' == *(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!\n");
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 ('\n' == *(buf + nDataLen)) //换行符
{
bLineEnd = TRUE; //接收数据结束
}else{
nDataLen += nReadLen; //增加数据长度
}
} return retVal;
}


TCP阻塞模式开发的更多相关文章

  1. Python socket(TCP阻塞模式)基础程式

    前置知识:Python基础语法,socket库 tips: 1. 默认HOST_IP:127.0.0.1 2. 默认HOST_PORT:7676 参考代码: 1. 客户端程式 #!/usr/bin/e ...

  2. TCP同步与异步及阻塞模式,多线程+阻塞模式,非阻塞模式简单介绍

    首先我简单介绍一下同步TCP编程 与异步TCP编程. 在服务端我们通常用一个TcpListener来监听一个IP和端口.客户端来一个请求的连接,在服务端可以用同步的方式来接收,也可以用异步的方式去接收 ...

  3. Socket 阻塞模式和非阻塞模式

    阻塞I/O模型: 简介:进程会一直阻塞,直到数据拷贝 完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好. 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返 ...

  4. <摘录>详谈高性能TCP服务器的开发

    对于开发一款高性能服务器程序,广大服务器开发人员在一直为之奋斗和努力.其中一个影响服务器的重要瓶颈就是服务器的网络处理模块.如果一款服务器程序不能及时的处理用户的数据.则服务器的上层业务逻辑再高效也是 ...

  5. IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)

    同步非阻塞模式(NonBlocking IO) 在非阻塞模式中,发出Socket的accept()和read()操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个信息.也 ...

  6. IO通信模型(一)同步阻塞模式BIO(Blocking IO)

    几个概念 阻塞IO 和非阻塞IO 这两个概念是程序级别的.主要描述的是程序请求操作系统IO操作后,如果IO资源没有准备好,那么程序该如何处理的问题:前者等待:后者继续执行(但是使用线程一直轮询,直到有 ...

  7. Linux网络编程:基于TCP的程序开发回顾篇《转》

    面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你 ...

  8. 开源基于asio的网络通信框架asio2,支持TCP,UDP,HTTP,RPC,SSL,跨平台,支持可靠UDP,支持TCP自动拆包,TCP数据报模式等

    开源基于asio的网络通信框架asio2,支持TCP,UDP,HTTP,RPC,SSL,跨平台,支持可靠UDP,支持TCP自动拆包,TCP数据报模式等 C++开发网络通信程序时用asio是个不错的选择 ...

  9. 《连载 | 物联网框架ServerSuperIO教程》- 6.并发通讯模式开发及注意事项

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

随机推荐

  1. 利用Teensy进行em410x卡模拟以及暴力破解em410x类门禁系统

    什么是低频?什么是EM410x? 首先,我不得不再次提一下那些工作在125khz频率下的低频卡(如:EM410X之类的),以便大家更好的阅读以下的内容. 什么是低频?以下就是低频的解释: 低频(LF, ...

  2. webbench源码学习-->命令行选项解析函数getopt和getopt_long函数

    对于webbench这个网站压力测试工具网上介绍的很多,有深度详解剖析的,对于背景就不在提了, 听说最多可以模拟3万个并发连接去测试网站的负载能力,这里主要是学习了一下它的源码,做点 笔记. 官方介绍 ...

  3. 修改类不重启tomcat 自动加载项目

    可以修改类不用重启Tomcat加载整个项目(手工启动)     配置reloadable=true(自动重载)     使用Debug模式,前提是仅限于局部修改.(修改类不用重启--热加载) Tomc ...

  4. 前端开发 —— google chart 的使用

    1. 引入所需的 js 库 在 <head></head>中 <script src="https://ajax.googleapis.com/ajax/lib ...

  5. SPSS教程学习笔记1:K个独立样本秩和检验及多重比较 (转载) (非参数假设检验)

    本文地址:http://www.datasoldier.net/archives/173版权声明:本文为原创文章,版权归 数据小兵 所有,欢迎分享本文,转载请保留出处!     方差分析经常会出现不满 ...

  6. c++ json 详解

    一. 使用jsoncpp解析json Jsoncpp是个跨平台的开源库,首先从http://jsoncpp.sourceforge.net/上下载jsoncpp库源码,我下载的是v0.5.0,压缩包大 ...

  7. 轻松制作儿童趣味算术软件 - imsoft.cnblogs

    轻松制作儿童趣味算术软件 马震安 电脑爱好者 2014-07-23 08:38技巧 0 条评论 标签:软件   兴趣是学习的动力,以动感的软件和自动判断得分的形式测试孩子的算术能力,总要比在白纸上出几 ...

  8. 【HDU5421】Victor and String(回文树)

    [HDU5421]Victor and String(回文树) 题面 Vjudge 大意: 你需要支持以下操作: 动态在前端插入一个字符 动态在后端插入一个字符 回答当前本质不同的回文串个数 回答当前 ...

  9. Luogu 3245 大数

    Luogu 3245 大数 开始就想 \(10\) 进制 \(hash\) ,\(Hash(r)\equiv Hash(l-1)\cdot 10^{r-l+1}\) ,感觉没什么美妙的性质啊... 然 ...

  10. hdu1227 dp

    题意:在一条路上有 n 个站点,并给定了每个站点的坐标,然后想要在 k 个站点旁边分别各建一个补给站,求所有站点到最近的补给站的距离和的最小值. 是的,毫无疑问,显然是 DP 问题,但是这题怎么递推还 ...