windows套接字阻塞模式编程实例
一、阻塞模式套接字服务端和客户端的运行流程如下:
1.1 服务器运行过程如下:
1.服务器启动后,等待客户端的连接请求。
2.当收到客户端的请求后,在界面上显示该客户端的IP地址和端口,以及“Hello,Server!”问候语。
3.服务器向该客户端应答“Hello,Clinet!”问候语。
4.服务器退出。
1.2客户端运行过程如下:
1.客户端启动后,向服务器发起连接请求。
2.当连接请求被接受后,客户端向服务器发送“Hello,Server!”问候语。
3.等待服务器的应答。
4.当客户端收到服务器的“Hello,Clinet!”应答后,客户端退出。
1.3 客户端和服务器端工作流程如下:
二、实例
2.1 服务器端:Server.cpp
- #include<iostream>
- #include<winsock2.h>
- #include<string>
- #pragma comment(lib,"ws2_32.lib")
- using namespace std;
- #define SERVER_EXIT_OK 0
- #define SERVER_DLL_ERROR 1
- #define SERVER_API_ERROR 2
- #define SERVERPORT 8888
- #define MAX_NUM_BUF 64
- //全局变量
- char bufRecv[MAX_NUM_BUF];//读缓冲区
- char bufSend[MAX_NUM_BUF];//写缓冲区
- SOCKET sServer;//服务器监听套接字
- SOCKET sClient;//接受客户端套接字
- bool bConning;//与客户端的连接状态变量
- //函数
- void InitMember(void);
- void ShowSocketMsg(char* str);
- int HandleSocketError(char* str);
- BOOL RecvLine(SOCKET s, char *buf);//读取一行数据
- BOOL SendLine(SOCKET s,char * buf);//发送一行数据
- int ExitClient(int nExit);//退出程序
- int main(int argc,char*argv[])
- {
- //调用初始化函数,进行相关初始化工作
- InitMember();
- //Windows Sockets动态库初始化
- WORD wVersionRequseted;
- WSADATA wsaData;
- int retVal;
- wVersionRequseted = MAKEWORD(,);
- retVal = WSAStartup(wVersionRequseted,&wsaData);
- if (retVal!=)
- {
- ShowSocketMsg("初始化动态连接库失败");
- return SERVER_DLL_ERROR;
- }
- //确保Winsock dll支持2.2
- if (LOBYTE(wsaData.wVersion)!=||HIBYTE(wsaData.wVersion!=))
- {
- ShowSocketMsg("没有发现动态链接库");
- return SERVER_DLL_ERROR;
- }
- //创建套接字
- sServer = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if (INVALID_SOCKET==sServer)
- {
- return HandleSocketError("Faild socket()!");
- }
- //服务器套接字地址
- SOCKADDR_IN addrServer;
- addrServer.sin_family = AF_INET;
- addrServer.sin_port = htons(SERVERPORT);
- addrServer.sin_addr.S_un.S_addr = INADDR_ANY;
- //绑定套接字
- retVal = bind(sServer,(sockaddr*)&addrServer,sizeof(addrServer));
- if (SOCKET_ERROR==retVal)
- {
- closesocket(sServer);
- return HandleSocketError("绑定套接字失败");
- }
- //监听
- retVal = listen(sServer,);
- if (SOCKET_ERROR==retVal)
- {
- closesocket(sServer);
- return HandleSocketError("监听失败");
- }
- cout << "服务器开始初始化成功!" << endl;
- cout << "等待客户端的连接...." << endl;
- //接受客户端的请求
- sockaddr_in addrClient;
- int addrClientLen = sizeof(addrClient);
- sClient = accept(sServer,(sockaddr*)&addrClient,&addrClientLen);
- if (SOCKET_ERROR==sClient)
- {
- closesocket(sServer);
- return HandleSocketError("接受客户端请求失败");
- }
- //显示客户端的IP和端口
- char *pClientIP = inet_ntoa(addrClient.sin_addr);
- u_short clientPort = ntohs(addrClient.sin_port);
- cout << "接受到来自客户端的请求:" << endl;
- cout << "客户端的IP:" << pClientIP << endl;
- cout << "客户端的端口:" << 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 << "服务器正在退出>>>>>" << endl;
- //退出
- return ExitClient(SERVER_EXIT_OK);
- getchar();
- return ;
- }
- //初始化成员变量
- void InitMember(void)
- {
- //初始化缓冲区
- memset(bufRecv, , MAX_NUM_BUF);
- memset(bufSend, , MAX_NUM_BUF);
- //初始化
- sServer = INVALID_SOCKET;
- sClient = INVALID_SOCKET;
- //无连接状态
- bConning = FALSE;
- }
- void ShowSocketMsg(char* str)
- {
- MessageBox(NULL,(LPCWSTR)str,(LPCWSTR)"SERVER_ERROR",MB_OK);
- }
- int HandleSocketError(char * str)
- {
- ShowSocketMsg(str);//显示错误
- WSACleanup();//卸载Windows socket DLL
- return SERVER_API_ERROR;//退出应用程序
- }
- 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 nErrorCode = WSAGetLastError();
- if (WSAENOTCONN==nErrorCode)
- {
- ShowSocketMsg("套接字未连接");
- }
- else if (WSAESHUTDOWN==nErrorCode)
- {
- ShowSocketMsg("套接字已经关闭");
- }
- else if (WSAETIMEDOUT == nErrorCode)
- {
- ShowSocketMsg("连接已断开!");
- }
- else if (WSAECONNRESET == nErrorCode)
- {
- ShowSocketMsg("一个现存的远程主机上运行的客户端被强制关闭!");
- }
- else {}
- retVal = FALSE; //读数据失败
- break;
- }
- if (nReadLen==)//客户端关闭
- {
- retVal = FALSE;
- break;
- }
- //读入数据
- if (*(buf+nDataLen)=='\n')
- {
- bLineEnd = TRUE;//接受数据结束
- }
- else
- {
- nDataLen += nReadLen;//增加数据长度
- }
- }
- return retVal;
- }
- BOOL SendLine(SOCKET s, char * buf)
- {
- int retVal=;//返回值
- retVal = send(s, buf, strlen(buf), );//一次发送
- //错误处理
- if (SOCKET_ERROR == retVal)
- {
- int nErrCode = WSAGetLastError();//错误代码
- if (WSAENOTCONN == nErrCode)
- {
- ShowSocketMsg("套接字未连接");
- }
- else if (WSAESHUTDOWN == nErrCode)
- {
- ShowSocketMsg("套接字已关闭!");
- }
- else if (WSAETIMEDOUT == nErrCode)
- {
- ShowSocketMsg("连接已断开!");
- }
- else {}
- return FALSE; //发送失败
- }
- return TRUE;
- }
- int ExitClient(int nExit)
- {
- closesocket(sServer); //关闭监听套接字
- closesocket(sClient); //关闭连接客户端套接接
- WSACleanup(); //卸载Windows sockets DLL 清理内存
- return nExit; //退出
- }
2.2 客户端:Client.cpp
- #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 8888//服务器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(, );
- retVal = WSAStartup(wVersionRequested, (LPWSADATA)&wsaData);
- if ( != retVal)
- {
- MessageBox(NULL, (LPCWSTR)"初始化动态链接库失败!",(LPCWSTR) "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 << "客户端初始化成功!" << endl;
- cout << "准备连接到服务器..." << 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, (sockaddr*)&addrServ, sizeof(addrServ));
- if (SOCKET_ERROR == retVal)
- {
- ShowErrorMsg(); //显示错误信息
- return ExitClient(CLIENT_API_ERROR); //退出
- }
- else {
- bConning = TRUE; //连接服务器成功
- }
- //连接服务器成功
- cout << "连接服务器成功!" << endl;
- //向服务器发送数据
- strcpy_s(bufSend, "Hello,Server!\n");
- retVal = send(sHost, bufSend, strlen(bufSend), );
- 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, , NULL);
- //显示错误信息
- if (hlocal != NULL)
- {
- MessageBox(NULL, (LPCWSTR)LocalLock(hlocal), (LPCWSTR)"CLIENT ERROR", MB_OK);
- LocalFree(hlocal);
- }
- }
- /*
- * 初始化成员变量
- */
- void InitMember(void)
- {
- //初始化读和写缓冲区
- memset(bufRecv, , MAX_NUM_BUF);
- memset(bufSend, , MAX_NUM_BUF);
- //初始化
- sHost = INVALID_SOCKET;
- //没有连接状态
- bConning = FALSE;
- }
- /*
- * 退出
- */
- int ExitClient(int nExit)
- {
- closesocket(sHost); //关闭套接字
- WSACleanup(); //卸载Windows sockets DLL 清理内存
- //显示退出信息
- cout << "客户端正在退出..." << endl;
- Sleep();
- 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)
- {
- retVal = FALSE; //读数据失败
- break; //跳出循环
- }
- if ( == nReadLen)//客户端关闭
- {
- retVal = FALSE; //读数据失败
- break; //跳出循环
- }
- //读入数据
- if ('\n' == *(buf + nDataLen)) //换行符
- {
- bLineEnd = TRUE; //接收数据结束
- }
- else {
- nDataLen += nReadLen; //增加数据长度
- }
- }
- return retVal;
- }
windows套接字阻塞模式编程实例的更多相关文章
- TCP/UDP套接字 java socket编程实例
网络协议七层结构: 什么是Socket? socket(套接字)是两个程序之间通过双向信道进行数据交换的端,可以理解为接口.使用socket编程也称为网络编程,socket只是接口并不是网络通信协议. ...
- windows套接字相关函数
windows套接字相关函数 作者:vpoet mail:vpoet_sir@163.com 我们学习TCP/IP协议无非是利用这些协议进行通信开发,然而如果让我们自己来直接根据协议规则和协议格式来进 ...
- 使用命名管道的OVERLAPPED方式实现非阻塞模式编程 .
命令管道是进程间通讯的一种常用方式,对于命令管道的介绍可以参考别的资料和书籍,这里推荐一个<VC++下命名管道编程的原理及实现>这篇博文,写得比较清楚.但是都是介绍了阻塞模式的编程,我这里 ...
- 缺少网络连接需要的Windows套接字注册表项(浏览器无法连网)
缺少网络连接需要的Windows套接字注册表项(浏览器无法连网) CreateTime--2018年4月25日14:17:42 Author:Marydon 1.异常信息 此计算机上缺少一个或多个 ...
- Python中利用原始套接字进行网络编程的示例
Python中利用原始套接字进行网络编程的示例 在实验中需要自己构造单独的HTTP数据报文,而使用SOCK_STREAM进行发送数据包,需要进行完整的TCP交互. 因此想使用原始套接字进行编程,直接构 ...
- 基于TCP的socket套接字的网络编程(客户端/服务端模式)
于数据完整性要求较高的场合,就应采用TCP协议. IP网络层提供IP寻址和路由.因为在网络上数据可以经由多条线路到达目的地,网络层负责找出最佳的传输线路. IP地址与数据包: IP层就是把数据分组从一 ...
- java套接字(socket)实例
客户端socket 流程: 1.连接远程主机 2.发送数据 3.接收数据 4.关闭流与socket连接 实例: import java.io.*; import java.net.Socket; im ...
- 5-tcp套接字服务端编程
import socket 1.创建套接字 sockfd= socket.socket(socket_family = AF_INIT,socket_type=SOCK_STREAM,proto) 功 ...
- iptables开启后造成本地套接字阻塞的问题
前段时间,我使用iptables实现了针对IP地址与MAC地址的白名单功能,即将INPUT链的默认规则设为DROP: iptables -P INPUT DROP 这样就能拒绝一切外来报文.随后只需要 ...
随机推荐
- es6的class关键字与es5的构造函数
1,构造函数 function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function () { ret ...
- HBase调优案例(一)——建表长时间等待最后失败
现象: 1.在HBase Shell里执行建表操作会等很久,最终失败: 2.通过代码侧进行建表同样不能成功. 原因排查: 1.查询HMaster日志,发现有接收到建表(create)的RPC请求: ...
- 前端每日实战:161# 视频演示如何用纯 CSS 创作一张纪念卓别林的卡片(没有笑声的一天就是被荒废的一天)
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/WaaBNV 可交互视频 此视频是可 ...
- python正则之模式re.I re.M
re.I 忽略大小写 >>> re.match(r"A","abc",re.I) <_sre.SRE_Match object at 0 ...
- PTA编程总结二
7-1 币值转换 (20 分) 输入一个整数(位数不超过9位)代表一个人民币值(单位为元),请转换成财务要求的大写中文格式.如23108元,转换后变成“贰万叁仟壹百零捌”元.为了简化输出,用小写英文字 ...
- SPEL 表达式解析
Spring Expression Language 解析器 SPEL解析过程 使用 ExpressionParser 基于 ParserContext 将字符串解析为 Expression, Exp ...
- Python 笔试集(3):编译/解释?动态/静态?强/弱?Python 是一门怎样的语言
面试题 解释/编译?动态/静态?强/弱?Python 到底是一门怎样的语言? 编译 or 解释? 编译.解释都是指将(与人类亲和的)编程语言翻译成(计算机能够理解的)机器语言(Machine code ...
- LoadRunner之关联
一.什么是关联 关联就是将服务器动态返回变化的值保存为一个参数以供后面需要用到的地方使用. 二.什么时候需要关联 1.服务器返回中存在动态变化的值,一般是类似session.token这样的无规则数据 ...
- MinGW GCC 9.1 2019年5月3日 出炉啦
GNU 2019-05-03 发布了 GCC 9.1 https://gcc.gnu.org/onlinedocs/9.1.0/ 有详细的说明MinGW 上可用的 GCC 9.1 版本下载地址 [ m ...
- Flink容错机制
Flink的Fault Tolerance,是在在Chandy Lamport Algorithm的基础上扩展实现了一套分布式Checkpointing机制,这个机制在论文"Lightwei ...