在阻塞模式下,在I/O操作完成前,执行的操作函数将一直等候而不会立即返回,该函数所在的线程会阻塞在这里。相反,在非阻塞模式下,套接字函数立即返回,而不管I/O是否完成。

重点知识和思想:

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

1、不管阻塞和非阻塞模式,最关键的两个数据是通过accept()函数返回的客户端套接字和客户端地址。

原因在于:

客户端套接字相当于一个句柄(这样理解其实不正确,但是容易理解),也相当于独一无二的标识ID。只有通过这个客户端套接字标识,才知道向哪一个客户端返回数据。(比如,服务器收到N个客户端的连接请求的情况下...)。

2、如何知道客户端关闭连接?

通过recv()函数,如果返回为0,表示客户端关闭连接。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#生产者和消费者模式

#完整代码#

#include <iostream>
#include <WINSOCK2.H>
#pragma comment(lib, "wsock32.lib") #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端口; char bufRecv[MAX_PATH]; //读缓冲区;
char bufSend[MAX_PATH]; //写缓冲区;
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();
WSADATA wsaData; //Windows sockets DLL版本信息
int retVal; //调用Windows sockets API返回值
retVal = WSAStartup(MAKEWORD(, ), &wsaData);
if ( != retVal)
{
ShowSocketMsg("找不到可用的Socket DLL!");
return SERVER_DLL_REEOR;
}
if (LOBYTE(wsaData.wVersion) != || HIBYTE(wsaData.wVersion) != )
{
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, );//开始监听;
if (SOCKET_ERROR == retVal)
{
closesocket(sServer);
return HandleSocketError("Failed listen()!");
} std::cout << "Server succeeded!" <<std::endl;//等待客户端的连接;
std::cout << "Waiting for new clients..." <<std::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);
std::cout << "Accept a client." <<std::endl;
std::cout << "IP: " << pClientIP <<std::endl;
std::cout << "Port: " << clientPort <<std::endl; if (!RecvLine(sClient, bufRecv))//接收客户端数据;
{
return ExitClient(SERVER_API_ERROR);
} std::cout << bufRecv <<std::endl;//显示客户端数据; strcpy_s(bufSend, "Hello,Client!\n");//向客户端发送数据;
if (!SendLine(sClient, bufSend))
{
return ExitClient(SERVER_API_ERROR);
}
std::cout << "Server exiting..." <<std::endl;//显示退出信息;
return ExitClient(SERVER_EXIT_OK);
} void InitMember(void)
{
memset(bufRecv, , MAX_PATH);
memset(bufSend, , MAX_PATH);
sServer = INVALID_SOCKET;
sClient = INVALID_SOCKET;
bConning = FALSE;
} int ExitClient(int nExit)
{
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return nExit;
} BOOL RecvLine(SOCKET s, char* buf)
{
BOOL retVal = TRUE; //返回值
BOOL bLineEnd = FALSE; //行结束
int nReadLen = ; //读入字节数
int nDataLen = ; //数据长度
while (!bLineEnd && bConning) //与客户端连接 没有换行
{
nReadLen = recv(s, buf + nDataLen, , ); //阻塞位置
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 ( == 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), ); //阻塞位置
//错误处理
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);
}

winSockets编程(四)阻塞模式(服务端)的更多相关文章

  1. JAVA之旅(三十四)——自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫

    JAVA之旅(三十四)--自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫 我们接着来说网络编程,TCP 一.自定义服务端 我们直接写一个服务端,让本机去连接 ...

  2. 网络版shell之网络编程练习篇--telnet服务端

    网络版shell之网络编程练习篇--telnet服务端   以前写过一个shell命令解释器,对与shell命令解释器的执行流程有了清晰的认识,这段时间学习网络编程,至于网络编程的细节以及知识点,已经 ...

  3. socket编程,简单多线程服务端测试程序

    socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.acce ...

  4. winsock 编程(简单客户&服务端通信实现)

    winsock 编程(简单客户&服务端通信实现) 双向通信:Client send message to Server, and if  Server receive the message, ...

  5. Zookeeper 源码(四)Zookeeper 服务端源码

    Zookeeper 源码(四)Zookeeper 服务端源码 Zookeeper 服务端的启动入口为 QuorumPeerMain public static void main(String[] a ...

  6. Socket网络编程(2)--服务端实现

    中秋了,首先祝大家中秋快乐,闲着无事在家整一个socket的聊天程序,有点仿QQ界面,就是瞎折腾,不知道最后是不是能将所有功能实现. 如果你对socket不了解,请看这篇文章:http://www.c ...

  7. 基于C++简单Windows API的socket编程(阻塞模式)

    1. 概述:简单的基于Windows API的socket点对点聊天程序,为了方便初学者,本文代码均采用阻塞原理编写. 2. 代码样例 Server.cpp(服务端) #include <cst ...

  8. 网络编程基础_4.1TCP_服务端

    TCP_服务端 #include <stdio.h> // 1. 包含必要的头文件和库, 必须位于 windows之前 #include <WinSock2.h> #pragm ...

  9. 四、eureka服务端同步注册操作

    所有文章 https://www.cnblogs.com/lay2017/p/11908715.html 正文 在eureka服务端注册服务一文中,我们提到register方法做了两件事 1)注册服务 ...

  10. python 网络编程(四)---UDP服务端客户端

    1.服务器端 UDP服务器建立与TCP相类似,具体比较如下: 补充下,第四步:不必使用listen还有accept函数. 具体代码如下:(设置socket选项省略) import socket fro ...

随机推荐

  1. pom.xml中坐标的组成

    坐标=组织(也就是所谓的公司名称)+项目名称+版本(如果不加范围默认为compile)

  2. Python 内置函数 memoryview

    转载自:https://www.cnblogs.com/sesshoumaru/p/6035548.html 英文文档: class memoryview(obj) memoryview object ...

  3. 【Linux】关于路由跟踪指令traceroute

      稍有计算机常识的人都知道ping命令,是用来检查自己的主机是否与目标地址接通,自己的主机与目标地址的通讯包通讯速率,所谓的通讯包也就是那些什么TCP/IP,UDP包,这里说得通俗一点,比如,就拿这 ...

  4. hdu 1254(两个BFS) 推箱子

    http://acm.hdu.edu.cn/showproblem.php?pid=1254 首先,要判断人是不是可以从4到达箱子的位置2,而且不止判断一次,因为推动箱子一步后,人的位置也会改变,所以 ...

  5. JVM 类加载器 (二)

    1.类加载器(ClassLoader)负责加载class文件,class文件在文件开头有特定的文件标识,并且ClassLoader只负责 class 文件的加载,至于class文件是否能够运行则由Ex ...

  6. MySql数据库 sql查询增加序号的伪列

    在查询数据库的时候,我们有时候需要对查询出来的数据加上序列,1,2,3,……n 例如:我们根据表的某个字段排序后,要对这些数据加上序列,这个时候序号常常不是我们建表时设置好的自增的主键id,怎么办呢? ...

  7. spring+mybatis+mina+logback框架搭建

    第一次接触spring,之前从来没有学过spring,所以算是赶鸭子上架,花了差不多一个星期来搭建,中间遇到各种各样的问题,一度觉得这个框架搭建非常麻烦,没有一点技术含量,纯粹就是配置,很低级!但随着 ...

  8. 20172306《Java程序设计》第四周学习总结

    20172306 <Java程序设计>第四周学习总结 教材学习内容总结 第四章: 1. 类和对象的回顾:除了看书,我还上网找了一下两者的一些区别. 2. 编写类时,了解到初始化.形式参数. ...

  9. 201621123008 《Java程序设计》第13周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多个用户通过网 ...

  10. android xml解析中的null问题

    当我们从服务器或者xml文件加载xml进行解析的时候,往往报告 nullpointer 错误.这是原始代码: String short_name = doc.getElementsByTagName( ...