《Windows网络编程案例教程》-董相志 学习记录 阻塞/非阻塞套接字编程

2.3 阻塞/非阻塞套接字编程
阻塞套接字编程通信流程图

2.3.1 阻塞套接字客户机编程
1.启动并初始化Winsock2服务

WSADATA WsaDat;
WSAStartup(MAKEWORD(2,2),&WsaDat);

2.创建Socket

SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

3.解析服务器主机名、配置服务器地址、端口信息

struct hostent *host;
host=gethostbyname("localhost");
SOCKADDR_IN SockAddr;
SockAddr.sin_port=htons(8888);
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);
  1. 连接服务器
connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr));

5.接收数据并显示

char buffer[1024];
int nDataLength=recv(Socket,buffer,1024,0);
std::cout<<buffer;

6.断开套接字连接

shutdown(socket,SD_SEND);

7.关闭套接字

closesocket(socket);

8.关闭Winsock套接字服务,释放资源

WSACleanup();

程序2.4 阻塞式套接字客户机完整代码

//程序2.4 阻塞式套接字客户机完整代码
#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")int main()
{// 初始化 Winsock服务WSADATA WsaDat;if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0){std::cout<<"Winsock错误 - Winsock服务初始化失败!\r\n";WSACleanup();system("PAUSE");return 0;}// 创建套接字SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(Socket==INVALID_SOCKET){std::cout<<"套接字错误 -创建套接字失败!\r\n";WSACleanup();system("PAUSE");return 0;}// 主机名解析struct hostent *host;if((host=gethostbyname("localhost"))==NULL){std::cout<<"主机名解析失败!\r\n";WSACleanup();system("PAUSE");return 0;}// 初始化套接字地址结构信息SOCKADDR_IN SockAddr;SockAddr.sin_port=htons(8888);SockAddr.sin_family=AF_INET;SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);// 连接服务器if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0){std::cout<<"与服务器连接失败!\r\n";WSACleanup();system("PAUSE");return 0;}// 从服务接收信息并显示char buffer[1024];memset(buffer,0,1023);int inDataLength=recv(Socket,buffer,1024,0);std::cout<<buffer;// 断开套接字连接,不允许发送数据,但可以继续接收数据shutdown(Socket,SD_SEND);// 关闭套接字,释放资源closesocket(Socket);// 关闭Winsock服务,清理内存WSACleanup();system("PAUSE");return 0;
}

2.3.2 阻塞套接字服务器编程
1.启动并初始化Winsock2服务(与客户机同)

WSADATA WsaDat;
WSAStartup(MAKEWORD(2,2),&WsaDat);

2.创建Socket(与客户机同)

SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

3.填充服务器地址、端口信息到SOCKADDR_IN中(有变化)
与客户机相比变化的地方:
(1)删除主机名解析,因为服务器不需要去主动连接客户机
(2)服务器绑定的地址设置为INADDR_ANY,表示不限定客户机
不变的地方:
端口号仍为8888。
修改后的代码如下:SOCKADDR_IN serverInf;
4. 绑定服务器地址信息到套接字(新增步骤)

bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf));

5.侦听客户连接(新增步骤)

listen(Socket,1);

6.接受客户连接(新增步骤)

accept(Socket,NULL,NULL);

7.向客户机发送数据

char *szMessage="服务器说:有朋自远方来来,不亦乐乎\r\n";
send(Socket,szMessage,strlen(szMessage),0);

8.断开套接字连接,停止发送数据(与客户机同)

shutdown(socket,SD_SEND);

9.关闭套接字(与客户机同)

closesocket(socket);

10.关闭Winsock套接字服务,释放资源

WSACleanup();
serverInf.sin_family=AF_INET;
serverInf.sin_addr.s_addr=INADDR_ANY;
serverInf.sin_port=htons(8888);

程序2.5 阻塞式服务器完整代码

//程序2.5 阻塞式服务器完整代码#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")int main()
{//1 初始化 Winsock服务WSADATA WsaDat;if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0){std::cout<<"Winsock服务初始化失败!\r\n";WSACleanup();system("PAUSE");return 0;}//2 创建监听套接字SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(Socket==INVALID_SOCKET){std::cout<<"创建套接字失败!\r\n";WSACleanup();system("PAUSE");return 0;}//3 填充服务器地址、端口信息到SOCKADDR_IN中SOCKADDR_IN serverInf;serverInf.sin_family=AF_INET;serverInf.sin_addr.s_addr=INADDR_ANY;serverInf.sin_port=htons(8888);//4 绑定服务器地址信息到套接字if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR){std::cout<<"不能绑定地址信息到套接字!\r\n";WSACleanup();system("PAUSE");return 0;}//5 侦听客户连接listen(Socket,1);SOCKET TempSock=SOCKET_ERROR;//6 接受客户连接while(TempSock==SOCKET_ERROR){std::cout<<"服务器:正在等待来自客户机的连接...\r\n";TempSock=accept(Socket,NULL,NULL);}Socket=TempSock;std::cout<<"服务器:有客户机连接到达!\r\n\r\n";//7 向客户机发送数据char *szMessage="服务器说:有朋自远方来来,不亦乐乎\r\n";send(Socket,szMessage,strlen(szMessage),0);//8 断开套接字连接,不允许发送数据shutdown(Socket,SD_SEND);//9 关闭套接字,释放资源closesocket(Socket);//10 关闭Winsock服务,清理内存,释放资源WSACleanup();system("PAUSE");return 0;
}

调试:先运行服务器端,再运行客户端

(说明,本服务器案例只接受一个客户端的连接)
2.3.3 非阻塞套接字客户机编程
设置套接字工作模式的代码如下:

u_long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);

如果设置iMode=0 ,套接字将处于阻塞模式,设置iMode=1,套接字工作于非阻塞模式。

//程序2.6 非阻塞模式客户机完整代码#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")int main(void)
{WSADATA WsaDat;if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0){std::cout<<"Winsock错误 - Winsock初始化失败\r\n";WSACleanup();system("PAUSE");return 0;}// 创建套接字SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(Socket==INVALID_SOCKET){std::cout<<"Winsock错误 - 创建套接字失败!\r\n";WSACleanup();system("PAUSE");return 0;}// 解析主机名struct hostent *host;if((host=gethostbyname("localhost"))==NULL){std::cout<<"解析主机名失败!\r\n";WSACleanup();system("PAUSE");return 0;}// 配置套接字地址结构信息SOCKADDR_IN SockAddr;SockAddr.sin_port=htons(8888);SockAddr.sin_family=AF_INET;SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);// 连接服务器if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0){std::cout<<"连接服务器失败!\r\n";WSACleanup();system("PAUSE");return 0;}//  iMode!=0是阻塞模式u_long iMode=1;ioctlsocket(Socket,FIONBIO,&iMode);// 主循环for(;;){// 接收服务器信息char buffer[1024];memset(buffer,0,1023);int inDataLength=recv(Socket,buffer,1024,0);std::cout<<buffer;int nError=WSAGetLastError();if(nError!=WSAEWOULDBLOCK&&nError!=0){std::cout<<"Winsock错误码为: "<<nError<<"\r\n";std::cout<<"服务器断开连接!\r\n";// 断开套接字,只能接收不能发送shutdown(Socket,SD_SEND);// 关闭套接字closesocket(Socket);break;}Sleep(1000);}WSACleanup();system("PAUSE");return 0;
}

2.3.4 非阻塞套接字服务器编程
前面五个步骤完全相同:
1.初始化套接字
2.创建套接字
3.配置SOCKADDR_IN地址信息
4.在套接字上侦听
5.接受来自客户机的连接
以下开始改变:
6.设置套接字工作模式
为了让服务器工作于非阻塞模式,此处加入套接字工作模式设置:

u_long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);

7.构建主循环

// 主循环
for(;;)
{char *szMessage="非阻塞服务器说:有朋自远方来来,不亦乐乎\r\n";send(Socket,szMessage,strlen(szMessage),0);int nError=WSAGetLastError();if(nError!=WSAEWOULDBLOCK&&nError!=0){std::cout<<"Winsock错误码为: "<<nError<<"\r\n";std::cout<<"客户机断开连接!\r\n";// 断开套接字连接,不允许发送,可以接收shutdown(Socket,SD_SEND);// 关闭套接字closesocket(Socket);break;}Sleep(1000);
}

8.关闭套接字服务(断开套接字连接和关闭套接字放到了主循环里)

//程序2.7 非阻塞模式服务器完整代码#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")int main()
{WSADATA WsaDat;if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0){std::cout<<"Winsock服务初始化失败!\r\n";WSACleanup();system("PAUSE");return 0;}SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(Socket==INVALID_SOCKET){std::cout<<"创建套接字失败!\r\n";WSACleanup();system("PAUSE");return 0;}SOCKADDR_IN serverInf;serverInf.sin_family=AF_INET;serverInf.sin_addr.s_addr=INADDR_ANY;serverInf.sin_port=htons(8888);if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR){std::cout<<"套接字绑定失败!\r\n";WSACleanup();system("PAUSE");return 0;}listen(Socket,1);SOCKET TempSock=SOCKET_ERROR;while(TempSock==SOCKET_ERROR){std::cout<<"服务器:正在等待客户机连接...\r\n";TempSock=accept(Socket,NULL,NULL);}//  iMode!=0表示阻塞模式u_long iMode=1;ioctlsocket(Socket,FIONBIO,&iMode);Socket=TempSock;std::cout<<"服务器说:有新客户机连接到达!\r\n\r\n";// 主循环for(;;){char *szMessage="非阻塞服务器说:有朋自远方来来,不亦乐乎\r\n";send(Socket,szMessage,strlen(szMessage),0);int nError=WSAGetLastError();if(nError!=WSAEWOULDBLOCK&&nError!=0){std::cout<<"Winsock错误码为: "<<nError<<"\r\n";std::cout<<"客户机断开连接!\r\n";// 断开套接字,不允许发送,可以接收shutdown(Socket,SD_SEND);// 关闭套接字closesocket(Socket);break;}Sleep(1000);}WSACleanup();system("PAUSE");return 0;
}

运行结果:(先运行服务器端再运行客户端)

《Windows网络编程案例教程》-董相志 学习记录 阻塞/非阻塞套接字编程相关推荐

  1. Windows网络编程案例教程-董相志 学习记录 第一个网络程序hostent

    <Windows网络编程案例教程>-董相志 学习记录 第一个网络程序hostent 第一章 网络编程概述 1.3.5第一个网络程序--hostent 对主机的名称和地址解析 WinSock ...

  2. UNP学习笔记3——基本UDP套接字编程

    1 概述 TCP和UDP网络编程存在一些本质的差异,主要是由于传输层的差别:UDP是无连接的不可靠的数据报协议,而TCP是面向连接的字节流协议. 下图是典型的UDP客户端和服务器之间的通信流程.客户不 ...

  3. UNP学习笔记-第三章套接字编程

    套接字地址结构 地址转换函数 地址转换函数在地址的文本表达和存放在套接字地址结构中的二进制值之间进行转换. 例如IPv4中inet_addr, inet_ntoa .新函数:inet_pton,ine ...

  4. java套接字编程_Java套接字编程:教程

    java套接字编程 本教程是Java套接字编程的简介,从一个简单的客户机-服务器示例开始,该示例演示了Java I / O的基本功能. 将向您介绍原始的java.io软件包和NIO,即Java 1.4 ...

  5. python套接字编程_Python套接字编程(1)——socket模块与套接字编程

    在Python网络编程系列,我们主要学习以下内容: 5. 常见的Python异步编程框架 6. 协程在Python网络编程中的使用 本文介绍Python下的基本套接字编程,主要基于 socket 模块 ...

  6. 1.3.1 数据报套接字编程

    1.3  实现超链接 在网络应用过程中,特别是在Web程序中,超级链接用得非常普遍.其实使用VC技术,也可以实现超级链接功能.在本节的内容中,将介绍使用Visual C++ 6.0开发一个实现超级链接 ...

  7. 计算机网络套接字编程实验-TCP多进程并发服务器程序与单进程客户端程序(简单回声)

    1.实验系列 ·Linux NAP-Linux网络应用编程系列 2.实验目的 ·理解多进程(Multiprocess)相关基本概念,理解父子进程之间的关系与差异,熟练掌握基于fork()的多进程编程模 ...

  8. day26-2 基于TCP协议的套接字编程

    目录 基于TCP协议的套接字编程 套接字 套接字工作流程 基于TCP协议的套接字编程(简单) 服务端 客户端 基于TCP协议的套接字编程(循环) 服务端 客户端1 客户端2 基于TCP协议的套接字编程 ...

  9. Python 套接字编程

    Python 套接字编程学习历程 1.什么是socket? Socket中文译作:套接字,socket是来建立'通信'的基础,建立连接,传输数据'通信端点'. 每一个套接字就是一组接口与端口的组合,用 ...

最新文章

  1. mysql update 并发 慢_MySQL跑在CentOS 6 和 7上的性能比较
  2. 中文版!Python入门学习的三件法宝!附免费下载
  3. 九、OLTP 性能调整与优化--结语
  4. Objective-C基础语法高速入门
  5. linux文件的查看指令-cat-more-less
  6. 数字孪生应用白皮书_【研究报告】数字孪生应用白皮书(2020版)
  7. 归纳(四):树链剖分
  8. (6)FPGA面试题D触发器
  9. 向高端应用进军 杰和推高计算四路服务器
  10. 单片机c语言 教案,《单片机C语言》 课程教案.doc
  11. 自动化构建工作流--gulp
  12. 希捷移动硬盘linux,[转载]强列建议不要买seagate希捷移动硬盘!!!
  13. 3. 二叉哥的二叉树
  14. 实验2 格式化输入输出和分支语句
  15. 基于HFSS设计一种新型圆极化天线
  16. python从云端服务器读数据_云服务器简单实现Python自动运维
  17. 往事依稀浑似梦 都随风雨到心头 ——OI回忆录
  18. ✨数织游戏✨:Python 制作的成本一毛钱却诚意满满的小礼物!!
  19. 超级炫酷的idea特效power mode
  20. 【转载】AutoCAD:ObjectARX版本下载地址

热门文章

  1. vue思维导图(超详细)
  2. Linux:权限详解
  3. sprintf函数的使用
  4. 【Vue五分钟】 五分钟了解Vue组件的核心概念
  5. 以太坊客户端Ethereum Wallet与Geth区别简介
  6. netframework4 分32 64位吗_手机微信有两个版本,32位和64位,你的微信是多少位?...
  7. CHS和LBA逻辑块地址
  8. random函数的调用
  9. 7、门禁控制系统接线原理图,如何安装布线
  10. 名词解释第七十五讲:溢价