c++下基于windows socket的单线程服务器客户端程序(基于TCP协议)
今天自己编写了一个简单的c++服务器客户端程序,注释较详细,在此做个笔记。
windows下socket编程的主要流程可概括如下:初始化ws2_32.dll动态库-->创建套接字-->绑定地址信息-->服务器进行监听/客户端连接服务器-->数据交换-->关闭套接字对象。
服务器端:
#include <Winsock2.h>
#include <Ws2tcpip.h>
#include <iostream> #pragma comment(lib, "ws2_32.lib") //socket编程需要引用该库 using std::cerr;
using std::cout;
using std::endl; const char DEFAULT_PORT[] = "";
const int RECV_BUF_SIZE = ;
const size_t IP_BUF_SIZE = ; //服务器
int main() {
WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息
int i_result = ; //接收返回值
SOCKET sock_server = INVALID_SOCKET; //创建服务器套接字
SOCKET sock_client = INVALID_SOCKET; //创建客户端套接字
//addrinfo是getaddrinfo()函数用来保存主机地址信息的结构体
addrinfo *result = nullptr; //result是存储地址信息的链表
addrinfo hints;
//初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
i_result = WSAStartup(MAKEWORD(, ), &wsa_data);
if (i_result != ) {
cerr << "WSAStartup() function failed: " << i_result << "\n";
system("pause");
return ;
}
//用0填充内存区域,是ZeroMemory的更安全版本
SecureZeroMemory(&hints, sizeof(addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //流式套接字用于TCP协议
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE; //socket的地址会被用于bind()函数的调用
//确定服务器的地址与端口,将相关信息写入result中
i_result = getaddrinfo(nullptr, DEFAULT_PORT, &hints, &result);
if (i_result != ) {
cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return ;
}
//创建服务器套接字
sock_server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
//套接字创建失败
if (sock_server == INVALID_SOCKET) {
cerr << "socket() function failed with error: " << WSAGetLastError() << "\n";
//将getaddrinfo()函数动态分配的addrinfo中的地址信息释放掉
freeaddrinfo(result);
//释放套接字资源
WSACleanup();
system("pause");
return ;
}
//将服务器套接字与地址对象绑定,result->ai_addr是结构体的指针
i_result = bind(sock_server, result->ai_addr, static_cast<int>(result->ai_addrlen));
//绑定失败
if (i_result == SOCKET_ERROR) {
cerr << "bind() function failed with error: " << WSAGetLastError() << "\n";
freeaddrinfo(result);
closesocket(sock_server);
WSACleanup();
system("pause");
return ;
}
freeaddrinfo(result);
cout << "server started successfully..." << endl;
//开始监听
cout << "start listening..." << endl;
i_result = listen(sock_server, SOMAXCONN);
if (i_result == SOCKET_ERROR) {
cerr << "listen() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_server);
system("pause");
return ;
}
//接收客户端请求,获取客户端ip地址
SOCKADDR_IN addr_client;
int len_addr = sizeof(SOCKADDR_IN);
char ip_buf[IP_BUF_SIZE];
SecureZeroMemory(ip_buf, IP_BUF_SIZE);
sock_client = accept(sock_server, (SOCKADDR*)&addr_client, &len_addr);
if (sock_client == INVALID_SOCKET) {
cerr << "accept() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_server);
WSACleanup();
system("pause");
return ;
}
cout << "client connected..." << endl;
//ip地址转换
inet_ntop(AF_INET, &addr_client, ip_buf, IP_BUF_SIZE);
cout << "client ip address: " << ip_buf << endl;
//接收和发送数据
char recv_buf[RECV_BUF_SIZE];
int send_result = ;
do {
//不可缺少,若不将内存空间清零会输出乱码,这是因为输送过来的信息未必有256个字节
SecureZeroMemory(recv_buf, RECV_BUF_SIZE);
//标志位一般设置为0
i_result = recv(sock_client, recv_buf, RECV_BUF_SIZE, );
if (i_result > ) {
//exit表示客户端请求断开连接
if (strcmp(recv_buf, "exit") == ) {
cout << "client requests to close the connection..." << endl;
break;
}
//输出接收的字节数
cout << "Bytes received: " << i_result << endl;
cout << "message received: " << recv_buf << endl;
//向客户端发送接收到的数据
send_result = send(sock_client, recv_buf, i_result, );
if (send_result == SOCKET_ERROR) {
cerr << "send() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return ;
}
}
//i_result的值为0表示连接已经关闭
else if (i_result == ) {
cout << "connection closed..." << endl;
}
else {
cerr << "recv() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return ;
}
} while (i_result > ); //do...while语句后注意要有分号
//shutdown()禁用套接字的接收或发送功能
i_result = shutdown(sock_client, SD_SEND);
if (i_result == SOCKET_ERROR) {
cerr << "shutdown() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return ;
}
//关闭套接字
i_result = closesocket(sock_server);
WSACleanup();
cout << "socket closed..." << endl;
system("pause");
return ;
}
客户端:
#include <iostream>
#include <WinSock2.h>
#include <Ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") using std::cin;
using std::cerr;
using std::cout;
using std::endl;
using std::flush; const char DEFAULT_PORT[] = "";
const int SEND_BUF_SIZE = ; //客户端
int main() {
WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息
int i_result = ; //接收返回值
SOCKET sock_client = INVALID_SOCKET;
addrinfo *result = nullptr, hints;
//初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
i_result = WSAStartup(MAKEWORD(, ), &wsa_data);
if (i_result != ) {
cerr << "WSAStartup() function failed: " << i_result << "\n";
system("pause");
return ;
}
SecureZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
//
i_result = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
if (i_result != ) {
cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return ;
}
//创建套接字
sock_client = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (sock_client == INVALID_SOCKET) {
cerr << "socket() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return ;
}
//连接服务器
i_result = connect(sock_client, result->ai_addr, result->ai_addrlen);
if (i_result == SOCKET_ERROR) {
cerr << "connect() function failed with error: " << WSAGetLastError() << "\n";
WSACleanup();
system("pause");
return ;
}
cout << "connect server successfully..." << endl;
//
freeaddrinfo(result);
//
char send_buf[SEND_BUF_SIZE];
int recv_result = ;
//SecureZeroMemory(send_buf, SEND_BUF_SIZE);
do {
cout << "enter the message that you want to send: " << flush;
cin.getline(send_buf, SEND_BUF_SIZE);
i_result = send(sock_client, send_buf, static_cast<int>(strlen(send_buf)), );
if (i_result == SOCKET_ERROR) {
cerr << "send() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return ;
}
cout << "Bytes sent: " << i_result << endl;
//接收服务器返回的数据
recv_result = recv(sock_client, send_buf, SEND_BUF_SIZE, );
if (recv_result > ) {
cout << "feedback from server: " << send_buf << endl;
}
else if (recv_result == ) {
cout << "connection closed..." << endl;
}
else {
cerr << "recv() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return ;
}
} while (recv_result > );
//
i_result = shutdown(sock_client, SD_SEND);
if (i_result == SOCKET_ERROR) {
cerr << "shutdown() function failed with error: " << WSAGetLastError() << "\n";
closesocket(sock_client);
WSACleanup();
system("pause");
return ;
}
closesocket(sock_client);
WSACleanup();
cout << "socket closed..." << endl;
system("pause");
return ;
}
c++下基于windows socket的单线程服务器客户端程序(基于TCP协议)的更多相关文章
- c++下基于windows socket的多线程服务器(基于TCP协议)
之前用c++实现过基于windows socket的单线程TCP服务器(http://www.cnblogs.com/jzincnblogs/p/5170230.html),今天实现了一个多线程的版本 ...
- c++下基于windows socket的服务器客户端程序(基于UDP协议)
前天写了一个基于tcp协议的服务器客户端程序,今天写了一个基于UDP协议的,由于在上一篇使用TCP协议的服务器中注释已经较为详细,且许多api的调用是相同的,故不再另外注释. 使用UDP协议需要注意几 ...
- 客户端程序通过TCP通信传送"小文件"到服务器
客户端程序通过TCP通信传送"小文件"到服务器 [c#源码分享]客户端程序通过TCP通信传送"小文件"到服务器 源码 (不包含通信框架源码,通信框架源码请另行 ...
- 高并发服务器建议调小 TCP 协议的 time_wait 超时时间。
1. [推荐]高并发服务器建议调小 TCP 协议的 time_wait 超时时间. 说明:操作系统默认 240 秒后,才会关闭处于 time_wait 状态的连接,在高并发访问下,服 务器端会因为处于 ...
- TCP/IP协议学习(四) 基于C# Socket的Web服务器---静态资源处理
目录 1. C# Socket通讯 2. HTTP 解析引擎 3. 资源读取和返回 4. 服务器测试和代码下载 Web服务器是Web资源的宿主,它需要处理用户端浏览器的请求,并指定对应的Web资源返回 ...
- JAVA基础知识之网络编程——-TCP/IP协议,socket通信,服务器客户端通信demo
OSI模型分层 OSI模型是指国际标准化组织(ISO)提出的开放系统互连参考模型(Open System Interconnection Reference Model,OSI/RM),它将网络分为七 ...
- 使用 Socket 通信实现 FTP 客户端程序(来自IBM)
FTP 客户端如 FlashFXP,File Zilla 被广泛应用,原理上都是用底层的 Socket 来实现.FTP 客户端与服务器端进行数据交换必须建立两个套接字,一个作为命令通道,一个作为数据通 ...
- 使用Socket通信实现FTP客户端程序
FTP 客户端如 FlashFXP,File Zilla 被广泛应用,原理上都是用底层的 Socket 来实现.FTP 客户端与服务器端进行数据交换必须建立两个套接字,一个作为命令通道,一个作为数据通 ...
- UNIX网络编程——TCP回射服务器/客户端程序
下面通过最简单的客户端/服务器程序的实例来学习socket API. serv.c 程序的功能是从客户端读取字符然后直接回射回去: #include<stdio.h> #include&l ...
随机推荐
- 使用JavaScript / JQuery导出 html table 数据至 Excel 兼容IE/Chrome/Firefox
function fnExcelReport() { var tab_text="<table border='2px'><tr bgcolor='#87AFC6'> ...
- Linux基础※※※※Linux中的图形相关工具
kolourPaint类似于Win中个mspaint: Ubuntu安装:sudo apt-get install kolourpaint4 图1 kolourPaint界面 其他类似的画图工具见链接 ...
- 部署showdoc
1.下载 https://github.com/star7th/showdoc 2.解压 sudo tar -zvxf ~/showdoc-2.4.5.tar.gz -C /home/wwwroot/ ...
- [原][译][physX]phsyX3.3.4官方文档物理引擎基本概念和例子介绍
世界和物体: 物理世界包括集合的场景,每个包含的物体称为演员(Actors) 每个场景(Scene)都定义了自己的参考框架包含了所有的时间和空间 在不同的场景,演员不互相影响 演员通常有三种类型:刚体 ...
- ASCII 和 Unicode 编码的由来
大话数据结构上的说明: 网络博文的说明:
- yii 第一步
第一步:index.php // include Yii bootstrap filerequire_once(dirname(__FILE__).'/../../framework/yii.php' ...
- Go开发环境安装配置
访问下载地址:https://golang.org/dl/ 32位系统下载go1.8.1.linux-386.tar.gz,64位系统下载go1.8.1.linux-amd64.tar.gz, 假定你 ...
- Loading Xps from MemoryStream
A common way of loading XpsDocument is to load it from file: XpsDocument document = new XpsDocument( ...
- 20170501xlVBA销售订单整理一行转多行
Sub NextSeven_CodeFrame() Application.ScreenUpdating = False Application.DisplayAlerts = False Appli ...
- CF-499div2-E-裴蜀定理
E. Border time limit per test 1 second memory limit per test 256 megabytes input standard input outp ...