博客
关于我
windows网络编程 | 基于控制台的简单服务器/客户端程序(5.4小节随书案例)
阅读量:286 次
发布时间:2019-03-01

本文共 6958 字,大约阅读时间需要 23 分钟。

基于流式套接字的回射程序开发

5.4 编程举例

本节通过一个Windows控制台应用程序实现基于流式套接字的回射功能。回射是指服务器接收客户发来的字符,并将接收到的内容再次发送回客户端,以检测网络和主机运行状态。本节设计客户和服务器两个独立的网络应用程序,结合网络操作的基本步骤讲述流式套接字编程中各函数的使用方法。

5.4.1 基于流式套接字的回射客户端编程操作

客户端程序接收命令行参数argv[1]传入的服务器端地址,与服务器进行连接。Visual Studio编译器设置命令行参数方法:项目(右键)属性——》调试——》命令参数。

客户端完整代码:

#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#include
#include
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
int __cdecl main(int argc, char **argv) {
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL, *ptr = NULL, hints;
char sendbuf[] = "this is a test";
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
if (argc != 2) {
printf("usage: %s server-name\n", argv[0]);
return 1;
}
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
} else if (iResult == 0) {
printf("Connection closed\n");
} else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
closesocket(ConnectSocket);
WSACleanup();
return 0;
}

5.4.2 基于流式套接字的回射服务器端编程操作

服务器端完整代码:

#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#include
#include
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
int __cdecl main(void) {
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.aifamily = AF_INET;
hints.aisocktype = SOCK_STREAM;
hints.aiprotocol = IPPROTO_TCP;
hints.aiflags = AI_PASSIVE;
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
closesocket(ListenSocket);
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
iSendResult = send(ClientSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
} else if (iResult == 0) {
printf("Connection closing...\n");
} else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
closesocket(ClientSocket);
WSACleanup();
return 0;
}

运行实例

运行环境:Visual Studio 2019,Windows 10专业版。

1. 创建解决方案

新建工程,并创建两个项目,分别用于编写服务器端和客户端的程序。将上述代码写入各自的.cpp文件中。

2. 客户端设置

设置客户端命令行参数:鼠标右键cli项目——》属性,选择调试,在命令参数中输入服务器IP地址。由于是本地测试,这里使用本地环回地址127.0.0.1

3. 多项目启动设置

由于需要同时运行服务器和客户端两个程序,这里设置编译器为多项目启动方式。

3.1 设置多项目启动

右键解决方案——》属性,选择通用属性——》启动项目——》多个启动项目,将sercli都设置为启动。

3.2 设置启动顺序

在项目依赖项中选择cli项目依赖于ser

4. 启动运行

点击运行,运行结果如图所示。

转载地址:http://deio.baihongyu.com/

你可能感兴趣的文章
Nginx 配置解析:从基础到高级应用指南
查看>>
nginx+php的搭建
查看>>
nginx+tomcat+memcached
查看>>
nginx+Tomcat性能监控
查看>>
nginx+uwsgi+django
查看>>
Nginx-http-flv-module流媒体服务器搭建+模拟推流+flv.js在前端html和Vue中播放HTTP-FLV视频流
查看>>
nginx-vts + prometheus 监控nginx
查看>>
Nginx下配置codeigniter框架方法
查看>>
Nginx之二:nginx.conf简单配置(参数详解)
查看>>
Nginx代理websocket配置(解决websocket异常断开连接tcp连接不断问题)
查看>>
Nginx代理初探
查看>>
nginx代理地图服务--离线部署地图服务(地图数据篇.4)
查看>>
Nginx代理外网映射
查看>>
Nginx代理模式下 log-format 获取客户端真实IP
查看>>
Nginx代理静态资源(gis瓦片图片)实现非固定ip的url适配网络环境映射ip下的资源请求解决方案
查看>>
Nginx代理静态资源(gis瓦片图片)实现非固定ip的url适配网络环境映射ip下的资源请求解决方案
查看>>
Nginx反向代理与正向代理配置
查看>>
Nginx反向代理是什么意思?如何配置Nginx反向代理?
查看>>
nginx反向代理解决跨域问题,使本地调试更方便
查看>>
nginx启动脚本
查看>>