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 这样就能拒绝一切外来报文.随后只需要 ...
随机推荐
- PHP 发邮件《转》
导读:PHP自带的mail()函数,是php内置发邮件的函数,该函数虽然简单,但是要想真正可以发邮件得有很复杂的配置.不适合新手,以及项目实际的应用的开发. php的mail()函数复杂配置,使得直接 ...
- 使用Vue前端框架实现知乎日报app
这是:主页代码 <template> <view class="content"> <view class="uni-list"& ...
- 后盾网lavarel视频项目---页面post方式提交之后动态弹出错误信息
后盾网lavarel视频项目---页面post方式提交之后动态弹出错误信息 一.总结 一句话总结: 1.思路和我想的一样,有错误的时候弹出提示错误消息的模态框就好,没有错误的时候不管它 2.把模态框的 ...
- 使用SharpZIpLib写的压缩解压操作类
使用SharpZIpLib写的压缩解压操作类,已测试. public class ZipHelper { /// <summary> /// 压缩文件 /// </summary&g ...
- 安装Mantis出现的一些问题解决
1.去除 Warning: date_default_timezone_get() 打开config_inc.php, 增加: $g_default_timezone = 'RPC'; 2.去除 S ...
- Delphi XE2 之 FireMonkey 入门(36) - 控件基础: TForm
Delphi XE2 之 FireMonkey 入门(36) - 控件基础: TForm 当我第一次读取 Form1.StyleLookup 并期待出现 "formstyle" 时 ...
- linux查看硬盘信息
1. 通过内核查看硬盘信息 cat /sys/block/sda/device/model cat /sys/block/sda/device/vendor 2. 用过hdparm命令查看 hdpar ...
- linux 学习笔记二
笔记二 命令行格式 command [-options] parameter1 parameter2 ... 命令 选项 参数(1) 参数(2) options 和 参数 不是必须的 帮助命令 man ...
- 虚拟化 RemoteApp 远程接入 源码 免费
远程接入 RemoteApp 虚拟化 源码 免费 1.终端安装与配置: 此远程接入组件的运行原理与瑞友天翼.异速连.CTBS等市面上常见的远程接入产品一样,是透过Windows的终端服务来实现的,速度 ...
- vue--路由嵌套
路由嵌套的SPA实现的步骤: A(/a)组件需要嵌套B组件(/b)和C组件(/c) ①准备嵌套其它组价的父组件 指定一个容器在A组件指定一个容器<router-view></rout ...