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 ...
随机推荐
- 用 C# 计算 与 java 一致的unix时间戳 (长时间整形 如:1476956079961)
背景: 调用java提供接口,需要长时间整形作为验证. 预备知识: 1. java 的 System.currentTimeMillis() 计算的长整型,是从1970年1月1日开始,截止当前的毫秒数 ...
- deque_01
A.头尾 添加/移除 A.1.deque::push_back(elemValue); A.2.deque::pop_back(); A.3.deque::push_front(elemValue); ...
- jq 插件写法
1.一次声明一个函数 $.fn.函数名 = function([options]){} $.fn.red=function(options){ var defaults = { 'color': 'r ...
- url 中需要转义的字符
1. + URL 中+号表示空格 %2B 2. 空格 URL中的空格可以用+号或者编码 %20 3. / 分隔目录和子目录 %2F 4. ? 分隔实际的 URL 和参数 %3F 5. % 指 ...
- 20161226xlVBA演示文稿替换文字另存pdf
Const ModelText As String = "机构名称" Const ModelName As String = "测试文件.pptx" Sub N ...
- 4-10 辅助方法controll_name,;SanitizeHelper; 伪元素和scss中的&, @Media; cache介绍。
回顾知识点 1. 在application.html.erb中: <main class="<%= controller.controller_name%>"&g ...
- 3-30 flash(api),rescue_from(); logger简介
ActionDispatch::Flash < Objec pass temporary primitive-types (String, Array, Hash) between action ...
- CentOS 7 install Nginx
1. rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.r ...
- 2-18,19 搭建MySQL主从服务器并并通过mysql-proxy实现读写分离
MySQL主从服务器 实现方式: MySQL REPLICATION Replication可以实现将数据从一台数据库服务器(master)复制到一台或多台数据库服务器(slave) 默认情况下这种 ...
- UVA-818 Cutting Chains (位压缩+暴力搜索)
题目大意:一种环能打开和闭合.现在有n(1<=n<=15)个编号为1~n的环错综复杂的连接着,要打开一些环重新连接使这n个环能构成一条链,问最少需要打开几次环可达到目的? 题目分析:用二进 ...