当前位置: 首页 > news >正文

C++ - 网络编程之初始连接(Winsock2 概述、初始连接案例、初始连接案例解读)

一、Winsock2 概述

  • Winsock2(Windows Sockets 2)是微软提供的 Windows 平台网络编程库

二、初始连接案例

1、Server
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>#pragma comment(lib, "ws2_32.lib")using namespace std;const int listen_port = 12345;int main() {WSADATA wsaData;int WSAStartupResult = WSAStartup(MAKEWORD(2, 2), &wsaData);if (WSAStartupResult != 0) {cerr << "WSAStartup() failed: " << WSAStartupResult << endl;return 1;}SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (listenSocket == INVALID_SOCKET) {cerr << "socket() failed: " << WSAGetLastError() << endl;WSACleanup();return 1;}sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(listen_port);serverAddr.sin_addr.s_addr = INADDR_ANY;int bindResult = bind(listenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));if (bindResult == SOCKET_ERROR) {cerr << "bind() failed: " << WSAGetLastError() << endl;closesocket(listenSocket);WSACleanup();return 1;}if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) {cerr << "listen() failed: " << WSAGetLastError() << endl;closesocket(listenSocket);WSACleanup();return 1;}cout << "Server is listening on port " << listen_port << endl;sockaddr_in clientAddr;int clientAddrSize = sizeof(clientAddr);SOCKET clientSocket = accept(listenSocket, (sockaddr*)&clientAddr, &clientAddrSize);if (clientSocket == INVALID_SOCKET) {cerr << "accept() failed: " << WSAGetLastError() << endl;}char clientIP[INET_ADDRSTRLEN];inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN);cout << "Client connected from " << clientIP << ":" << ntohs(clientAddr.sin_port) << endl;return 0;
}
2、Client
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>#pragma comment(lib, "ws2_32.lib")using namespace std;int main() {WSADATA wsaData;int WSAStartupResult = WSAStartup(MAKEWORD(2, 2), &wsaData);if (WSAStartupResult != 0) {cerr << "WSAStartup() failed: " << WSAStartupResult << endl;return 1;}SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sock == INVALID_SOCKET) {cerr << "socket() failed: " << WSAGetLastError() << endl;WSACleanup();return 1;}sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(12345);inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);int ConnectionResult = connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr));if (ConnectionResult == SOCKET_ERROR) {cerr << "connect() failed: " << WSAGetLastError() << endl;closesocket(sock);WSACleanup();return 1;}cout << "Successfully connected to server!" << endl;closesocket(sock);WSACleanup();return 0;
}
3、Test
  1. 启动 Server,输出结果
# ServerServer is listening on port 12345
  1. 启动 Client,输出结果
# ClientSuccessfully connected to server!
# ServerClient connected from 127.0.0.1:63154

三、初始连接案例解读

1、Server
(1)头文件与库引入
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>#pragma comment(lib, "ws2_32.lib")using namespace std;
  1. winsock2.h 是 Winsock 编程的核心头文件,包含了大部分套接字函数和数据结构的定义

  2. ws2tcpip.h 提供 IP 地址转换等功能

  3. iostream 标准输入输出

  4. #pragma comment 指令用于链接 ws2_32.lib

  5. using namespace 启用命名空间 std

(2)初始化 Winsock 库
WSADATA wsaData;
int WSAStartupResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (WSAStartupResult != 0) {cerr << "WSAStartup() failed: " << WSAStartupResult << endl;return 1;
}
  1. WSADATA 结构用于接收库的详细信息

  2. WSAStartup() 是 Winsock 程序的第一个调用,用于初始化库,MAKEWORD(2, 2) 表示初始化 Winsock 2.2 版本

  3. 必须检查返回值,失败时应立即退出

(3)创建监听套接字
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket == INVALID_SOCKET) {cerr << "socket() failed: " << WSAGetLastError() << endl;WSACleanup();return 1;
}
  1. socket() 用于创建套接字,失败时返回 INVALID_SOCKET

  2. AF_INET 表示使用 IPv4 地址族,SOCK_STREAM 表示面向连接的 TCP 套接字,IPPROTO_TCP 表示指定 TCP 协议

  3. 失败时调用 WSAGetLastError() 获取错误代码,然后调用 WSACleanup() 释放资源

(4)设置服务端地址
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(listen_port);
serverAddr.sin_addr.s_addr = INADDR_ANY;
  1. sockaddr_in 结构用于指定服务器地址信息

  2. sin_family 表示地址族(IPv4),sin_port 表示端口号(使用 htons 将主机字节序转换为网络字节序),sin_addr.s_addr 使用的 INADDR_ANY 表示绑定到所有可用接口

(5)绑定套接字
int bindResult = bind(listenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
if (bindResult == SOCKET_ERROR) {cerr << "bind() failed: " << WSAGetLastError() << endl;closesocket(listenSocket);WSACleanup();return 1;
}
  1. bind() 将套接字与特定 IP 和端口关联,如果未发生错误,绑定返回 0,否则,返回 SOCKET_ERROR

  2. 失败时调用 WSAGetLastError() 获取错误代码,然后调用 closesocket() 关闭现有套接字,然后调用 WSACleanup() 释放资源

(6)开始监听
if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) {cerr << "listen() failed: " << WSAGetLastError() << endl;closesocket(listenSocket);WSACleanup();return 1;
}cout << "Server is listening on port " << listen_port << endl;
  1. listen() 使套接字进入监听状态,如果未发生错误,返回 0,否则,返回 SOCKET_ERROR

  2. SOMAXCONN 是系统允许的最大挂起连接数

  3. 失败时调用 WSAGetLastError() 获取错误代码,然后调用 closesocket() 关闭现有套接字,然后调用 WSACleanup() 释放资源

(7)接受客户端连接
sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
SOCKET clientSocket = accept(listenSocket, (sockaddr*)&clientAddr, &clientAddrSize);
if (clientSocket == INVALID_SOCKET) {cerr << "accept() failed: " << WSAGetLastError() << endl;
}
  1. clientAddr 结构用于获取客户端地址信息

  2. accept() 接受传入的连接请求,阻塞直到有客户端连接,返回一个新的套接字用于与客户端通信

(8)显示客户端信息
char clientIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN);
cout << "Client connected from " << clientIP << ":" << ntohs(clientAddr.sin_port) << endl;
  1. inet_ntop() 将二进制 IP 地址转换为可读字符串

  2. ntohs() 将网络字节序的端口转换为主机字节序

2、Client
(1)头文件与库引入
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>#pragma comment(lib, "ws2_32.lib")using namespace std;
  1. winsock2.h 是 Winsock 编程的核心头文件,包含了大部分套接字函数和数据结构的定义

  2. ws2tcpip.h 提供 IP 地址转换等功能

  3. iostream 标准输入输出

  4. #pragma comment 指令用于链接 ws2_32.lib

  5. using namespace 启用命名空间 std

(2)初始化 Winsock 库
WSADATA wsaData;
int WSAStartupResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (WSAStartupResult != 0) {cerr << "WSAStartup() failed: " << WSAStartupResult << endl;return 1;
}
(3)创建套接字
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {cerr << "socket() failed: " << WSAGetLastError() << endl;WSACleanup();return 1;
}
  1. socket() 用于创建套接字,失败时返回 INVALID_SOCKET

  2. AF_INET 表示使用 IPv4 地址族,SOCK_STREAM 表示面向连接的 TCP 套接字,IPPROTO_TCP 表示指定 TCP 协议

  3. 失败时调用 WSAGetLastError() 获取错误代码,然后调用 WSACleanup() 释放资源

(4)设置服务端地址
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
  1. sockaddr_in 结构用于指定服务器地址信息

  2. sin_family 表示地址族(IPv4),sin_port 表示端口号(使用 htons 将主机字节序转换为网络字节序),sin_addr 使用 inet_pton 将字符串 IP 转换为二进制格式

(5)连接服务端
int ConnectionResult = connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr));
if (ConnectionResult == SOCKET_ERROR) {cerr << "connect() failed: " << WSAGetLastError() << endl;closesocket(sock);WSACleanup();return 1;
}
  1. connect() 发起连接,如果成功,返回 0,否则,返回 SOCKET_ERROR

  2. 失败时调用 WSAGetLastError() 获取错误代码,然后调用 closesocket() 关闭现有套接字,然后调用 WSACleanup() 释放资源

http://www.xdnf.cn/news/519769.html

相关文章:

  • 封装、继承、多态的理解
  • Java面试实战:从Spring Boot到分布式缓存的深度探索
  • 程序代码篇---python获取http界面上按钮或者数据输入
  • 批量下载AlphaFold结构
  • leetcode刷题日记——翻转二叉树
  • 第11章 JDBC与MySQL数据库
  • UI架构的历史与基础入门
  • GOP模式调节画面质量讲解
  • 八股碎碎念01——HashMap原理
  • GESP编程能力等级认证C++3级1-数组1
  • 研读论文《Attention Is All You Need》(6)
  • 软考复习——部署
  • 嵌入式通信协议(二)——IIC总线
  • 《P5283 [十二省联考 2019] 异或粽子》
  • OpenAI Chat API 详解:打造智能对话应用的基石
  • 牛客网NC210769:孪生素数对问题解析与实现
  • 5月18日day29打卡
  • Listener method could not be invoked with the incoming message
  • 《C++与OpenCV实战:图像增强大核心算法详解》​​
  • [ctfshow web入门] web122
  • Git目录分析与第一个git commit文件
  • 20倍云台球机是一种高性能的监控设备
  • PortSwigger Labs CSRF详细教程
  • C++学习:六个月从基础到就业——C++17:string_view与filesystem
  • Vue3前端xlsx导出
  • 微服务项目->在线oj系统(Java版 - 3)
  • 王树森推荐系统公开课 排序02:Multi-gate Mixture-of-Experts (MMoE)
  • 【AI面试秘籍】| 第15期:大模型如何稳定输出合法JSON?
  • 【Linux笔记】——线程同步条件变量与生产者消费者模型的实现
  • GEE谷歌地球引擎批量下载逐日ERA5气象数据的方法