首页 > 系统相关 >突破编程_C++_网络编程(Windows 套接字(概述))

突破编程_C++_网络编程(Windows 套接字(概述))

时间:2024-04-05 16:01:38浏览次数:30  
标签:Windows 编程 C++ buffer clientSocket serverAddr printf 接字 WSAGetLastError

1 什么是 Window 套接字编程

1.1 基本概念

Windows 的套接字(Socket)是基于 Windows 操作系统的网络通信编程接口。它起源于 UNIX 系统的 Berkeley 套接字,但经过微软和第三方厂商的共同制定,形成了一套适用于 Windows 环境的标准,即 Windows Socket 规范,简称 WinSock。

Windows 的套接字提供了一种抽象层,使得应用程序能够通过网络进行通信,无论是在同一台计算机上还是在不同的计算机之间。它允许应用程序发送和接收数据包,以便与其他应用程序进行交互。同时,套接字也用于定义通信协议的类型,例如 TCP 套接字或 UDP 套接字,以满足不同的传输需求。

在使用 Windows 的套接字进行编程时,开发者需要遵循一定的步骤,包括创建套接字、绑定 IP 地址和端口号、监听连接请求、建立连接、发送和接收数据,以及最后关闭套接字等。这些步骤共同构成了基于 Windows 的套接字通信的基础流程。

1.2 套接字编程的基本步骤

Windows 套接字编程的基本步骤,针对 TCP 和 UDP 两种协议,有些许差异,具体如下:

(1)对于 TCP 协议:

  • 创建套接字:使用 socket() 函数创建一个套接字,并指定协议族(通常为 IPv4 或 IPv6)、套接字类型(对于 TCP,通常使用 SOCK_STREAM)以及协议(通常为 0,表示选择默认协议)。
  • 绑定地址和端口:使用 bind() 函数将套接字绑定到本地的 IP 地址和端口号上。这样,其他主机就可以通过这个地址和端口号与你的应用程序进行通信。
  • 监听连接(仅适用于服务器端):对于服务器端的套接字,使用 listen() 函数将其设置为监听模式,等待客户端的连接请求。
  • 接受或发起连接:
    • 服务器端:使用 accept() 函数接受客户端的连接请求,并返回一个新的套接字用于与该客户端通信。
    • 客户端:使用 connect() 函数向服务器发起连接请求。
  • 数据交换:
    • 发送数据:使用 send() 函数发送数据。
    • 接收数据:使用 recv() 函数接收数据。TCP是面向连接的协议,因此数据会按照发送的顺序到达接收端。
  • 关闭套接字:通信结束后,使用 close() 或 closesocket() 函数关闭套接字,释放资源。

(2)对于 UDP 协议:

  • 创建套接字:同样使用 socket() 函数创建套接字,但这次套接字类型应指定为 SOCK_DGRAM,表示数据报套接字。
  • 绑定地址和端口:同样使用 bind() 函数将套接字绑定到本地的 IP 地址和端口号上。
  • 数据交换:
    • 发送数据:使用 sendto() 函数发送数据,并指定目标地址和端口号。
    • 接收数据:使用 recvfrom() 函数接收数据,并获取发送方的地址和端口号。UDP是无连接的协议,因此数据可能不按照发送的顺序到达接收端,也可能出现丢失或重复的情况。
  • 关闭套接字:通信结束后,同样使用 close() 或 closesocket() 函数关闭套接字。

注意:这些步骤仅描述了 TCP 和 UDP 套接字编程的基本流程。在实际应用中,还需要考虑错误处理、并发处理、数据缓冲区管理等方面的问题。此外,对于复杂的网络应用,可能还需要使用多线程或多进程来处理多个并发连接和数据交换任务。

2 Windows 套接字编程示例(TCP)

在 Windows 环境下进行 TCP 套接字编程通常涉及创建套接字、绑定、监听、接受连接、发送和接收数据,以及关闭套接字等步骤。以下是一个简单的 TCP 服务器和客户端的示例代码。

2.1 TCP 服务器示例

#include <winsock2.h>  
#include <stdio.h>  
  
#pragma comment(lib, "ws2_32.lib")  
  
int main() {  
    WSADATA wsaData;  
    SOCKET serverSocket, clientSocket;  
    struct sockaddr_in serverAddr, clientAddr;  
    int addrlen = sizeof(clientAddr);  
    char buffer[1024] = {0};  
    int bytesSent, bytesRecv;  
  
    // 初始化Winsock  
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {  
        printf("WSAStartup failed: %d\n", WSAGetLastError());  
        return 1;  
    }  
  
    // 创建套接字  
    serverSocket = socket(AF_INET, SOCK_STREAM, 0);  
    if (serverSocket == INVALID_SOCKET) {  
        printf("Could not create socket: %d\n", WSAGetLastError());  
        WSACleanup();  
        return 1;  
    }  
  
    // 设置服务器地址信息  
    serverAddr.sin_family = AF_INET;  
    serverAddr.sin_addr.s_addr = INADDR_ANY;  
    serverAddr.sin_port = htons(12345); // 端口号  
  
    // 绑定套接字  
    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {  
        printf("Bind failed: %d\n", WSAGetLastError());  
        closesocket(serverSocket);  
        WSACleanup();  
        return 1;  
    }  
  
    // 监听连接请求  
    if (listen(serverSocket, 5) == SOCKET_ERROR) {  
        printf("Listen failed: %d\n", WSAGetLastError());  
        closesocket(serverSocket);  
        WSACleanup();  
        return 1;  
    }  
  
    printf("Server is listening on port 12345...\n");  
  
    // 接受客户端连接  
    clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &addrlen);  
    if (clientSocket == INVALID_SOCKET) {  
        printf("Accept failed: %d\n", WSAGetLastError());  
        closesocket(serverSocket);  
        WSACleanup();  
        return 1;  
    }  
  
    // 接收数据  
    bytesRecv = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);  
    if (bytesRecv > 0) {  
        buffer[bytesRecv] = '\0';  
        printf("Received: %s\n", buffer);  
    } else {  
        printf("recv failed: %d\n", WSAGetLastError());  
    }  
  
    // 发送响应  
    strcpy(buffer, "Hello from server!");  
    bytesSent = send(clientSocket, buffer, strlen(buffer), 0);  
    if (bytesSent == SOCKET_ERROR) {  
        printf("send failed: %d\n", WSAGetLastError());  
    } else {  
        printf("Sent: %s\n", buffer);  
    }  
  
    // 关闭套接字  
    closesocket(clientSocket);  
    closesocket(serverSocket);  
    WSACleanup();  
  
    return 0;  
}

在执行完服务端与客户端程序后,服务端程序的输出为:

Server is listening on port 12345...
Received: Hello from client!
Sent: Hello from server!

2.2 TCP 客户端示例

#include <winsock2.h>  
#include <stdio.h>  

#pragma comment(lib, "ws2_32.lib")  

int main() {
	WSADATA wsaData;
	SOCKET clientSocket;
	struct sockaddr_in serverAddr;
	char buffer[1024] = { 0 };
	int bytesSent, bytesRecv;

	// 初始化Winsock  
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		printf("WSAStartup failed: %d\n", WSAGetLastError());
		return 1;
	}

	// 创建套接字  
	clientSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (clientSocket == INVALID_SOCKET) {
		printf("Could not create socket: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// 设置服务器地址信息
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器IP地址,这里假设为本地地址
	serverAddr.sin_port = htons(12345); // 服务器端口号

	// 连接服务器  
	if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
		printf("Connect failed: %d\n", WSAGetLastError());
		closesocket(clientSocket);
		WSACleanup();
		return 1;
	}

	printf("Connected to server...\n");

	// 发送数据  
	strcpy(buffer, "Hello from client!");
	bytesSent = send(clientSocket, buffer, strlen(buffer), 0);
	if (bytesSent == SOCKET_ERROR) {
		printf("send failed: %d\n", WSAGetLastError());
	}
	else {
		printf("Sent: %s\n", buffer);
	}

	// 接收响应  
	bytesRecv = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
	if (bytesRecv > 0) {
		buffer[bytesRecv] = '\0';
		printf("Received: %s\n", buffer);
	}
	else {
		printf("recv failed: %d\n", WSAGetLastError());
	}

	// 关闭套接字  
	closesocket(clientSocket);
	WSACleanup();

	return 0;
}

在执行完服务端与客户端程序后,客户端程序的输出为:

Connected to server...
Sent: Hello from client!
Received: Hello from server!

3 Windows 套接字编程示例(UDP)

在 Windows 环境下,使用套接字(Socket)进行 UDP 编程涉及创建套接字、绑定套接字到特定的端口、发送和接收数据等步骤。以下是一个简单的 UDP 服务器和客户端示例代码。

3.1 UDP 服务器示例

#include <stdio.h>  
#include <stdlib.h>  
#include <winsock2.h>  
  
#pragma comment(lib, "ws2_32.lib")  
  
#define SERVER_PORT 12345  
#define BUFFER_SIZE 1024  
  
int main() {  
    WSADATA wsaData;  
    SOCKET serverSocket;  
    struct sockaddr_in serverAddr, clientAddr;  
    int addrlen = sizeof(clientAddr);  
    char buffer[BUFFER_SIZE];  
    int bytesRecv;  
  
    // 初始化Winsock  
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {  
        printf("WSAStartup failed: %d\n", WSAGetLastError());  
        return 1;  
    }  
  
    // 创建UDP套接字  
    serverSocket = socket(AF_INET, SOCK_DGRAM, 0);  
    if (serverSocket == INVALID_SOCKET) {  
        printf("Could not create socket: %d\n", WSAGetLastError());  
        WSACleanup();  
        return 1;  
    }  
  
    // 设置服务器地址信息  
    serverAddr.sin_family = AF_INET;  
    serverAddr.sin_addr.s_addr = INADDR_ANY;  
    serverAddr.sin_port = htons(SERVER_PORT);  
  
    // 绑定套接字到服务器地址  
    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {  
        printf("Bind failed: %d\n", WSAGetLastError());  
        closesocket(serverSocket);  
        WSACleanup();  
        return 1;  
    }  
  
    printf("UDP server is listening on port %d...\n", SERVER_PORT);  
  
    // 接收客户端数据  
    while (1) {  
        bytesRecv = recvfrom(serverSocket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&clientAddr, &addrlen);  
        if (bytesRecv > 0) {  
            buffer[bytesRecv] = '\0';  
            printf("Received from client: %s\n", buffer);  
        } else {  
            printf("recvfrom failed: %d\n", WSAGetLastError());  
            break;  
        }  
    }  
  
    // 关闭套接字和Winsock库  
    closesocket(serverSocket);  
    WSACleanup();  
  
    return 0;  
}

在执行完服务器与客户端程序后,服务器程序的输出为:

UDP server is listening on port 12345...
Received from client: Hello from UDP client!

3.2 UDP 客户端示例

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <winsock2.h>  

#pragma comment(lib, "ws2_32.lib")  

#define SERVER_IP "127.0.0.1"  
#define SERVER_PORT 12345  
#define BUFFER_SIZE 1024  

int main() {
	WSADATA wsaData;
	SOCKET clientSocket;
	struct sockaddr_in serverAddr;
	char buffer[BUFFER_SIZE];
	int bytesSent;

	// 初始化Winsock  
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		printf("WSAStartup failed: %d\n", WSAGetLastError());
		return 1;
	}

	// 创建UDP套接字  
	clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
	if (clientSocket == INVALID_SOCKET) {
		printf("Could not create socket: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// 设置服务器地址信息  
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
	serverAddr.sin_port = htons(SERVER_PORT);

	// 向服务器发送数据  
	strcpy(buffer, "Hello from UDP client!");
	bytesSent = sendto(clientSocket, buffer, strlen(buffer), 0, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
	if (bytesSent == SOCKET_ERROR) {
		printf("sendto failed: %d\n", WSAGetLastError());
	}
	else {
		printf("Sent: %s\n", buffer);
	}

	// 关闭套接字和Winsock库  
	closesocket(clientSocket);
	WSACleanup();

	system("pause");

	return 0;
}

在执行完服务器与客户端程序后,服务器程序的输出为:

Sent: Hello from UDP client!

标签:Windows,编程,C++,buffer,clientSocket,serverAddr,printf,接字,WSAGetLastError
From: https://blog.csdn.net/h8062651/article/details/137402388

相关文章

  • 二叉树计算【华为OD机试JAVA&Python&C++&JS题解】
    一.题目-二叉树计算给出一个二叉树如下图所示:6/79\/-26请由该二叉树生成一个新的二叉树,它满足其树中的每个节点将包含原始树中的左子树和右子树的和。20(7-2+9+6)/\-26\/......
  • 学生重新排队【华为OD机试JAVA&Python&C++&JS题解】
    一.题目-学生重新排队n个学生排成一排,学生编号分别是1到n,n为3的整倍数。老师随机抽签决定将所有学生分成m个3人的小组,n=3*m为了便于同组学生交流,老师决定将小组成员安排到一起,也就是同组成员彼此相连,同组任意两个成员输入描述:之间无其它组的成员。因此老师决定调整队伍,......
  • windows编程模型
    WinMain函数的定义int WINAPI WinMain(HINSTANCE hInstance,//应用程序实例HINSTANCE hPrevInstance,//上一个应用程序实例LPSTR lpCmdLine,//命令行参数int nShowCmd);//窗口显示的样式 WINAPI:是一个宏,它代表的是__stdcall(注意是两个下划线),表示的是参数传递......
  • FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
    ​FFmpeg内置了aac音频格式,在《FFmpeg开发实战:从零基础到短视频上线》一书的“5.2.2 Linux环境集成mp3lame”又介绍了如何给FFmpeg集成mp3格式,常见的音频文件除了这两种之外,还有ogg和amr两种格式也较常用。其中ogg格式的编解码依赖于libogg和libvorbis,而amr格式的编解码依赖于op......
  • 接龙序列(动态规划c++实现)
    题目对于一个长度为K的整数数列:A1,A2,…,AK,我们称之为接龙数列当且仅当Ai的首位数字恰好等于Ai−1的末位数字(2≤i≤K)。例如12,23,35,56,61,11是接龙数列;12,23,34,56不是接龙数列,因为56的首位数字不等于34的末位数字。所有长度为1的整数数列都是接龙数列......
  • Windows 11 RDP 设置自定义证书
    1.随便生成一个证书或者去freessl之类的地方申请一个证书2.将证书转换成pfx格式opensslpkcs12-export-inkeyprivate_key.key-incertificate.pem-certfileCACert.pem-outcertificate.pfx3.打开certlm右键个人->所有任务->导入,导入刚刚创建的pfx证书......
  • 【C++风云录】音频编程艺术:掌握VST、JUCE、JACK和PortAudio的技巧
    声音之旅:音频开发者指南前言音频处理是现代软件开发中不可或缺的一部分,无论是音乐制作软件、游戏开发还是通信应用都需要对音频数据进行处理。本文将介绍几种常用的音频处理库和框架,帮助开发者更好地理解和应用于实际项目中。欢迎订阅专栏:C++风云录文章目录声音之......
  • open c++ 自动设计阶梯轴UF_MODL_create_cyl1
    通过UF_MODL_create_cyl1自动设计阶梯轴 doubleTtotal=260; doubleL1=21.00; doubleL2=12.00; doubleL3=57.00; doubleL4=36.00; doubleL6=67.00; doubleL5=Ttotal-(L1+L2+L3+L4+L6); doubled1=55.00; doubled2=65.00; dou......
  • 给c++小白的教程3:变量
    哈喽大家好,又见面了变量可谓是c++中的一大重点,今天就来给大家讲解一下c++中的变量今天只讲c++自带的变量(不用别的头文件)定义变量用法:数据类型名称=内容输出:cout<<名称;首先是intint指整数变量,范围在-2147483648~2147483647(约21亿)之间用法:inta=23333intb=1234567......
  • Windows窗体应用保存操作日志
    应用界面按下“button1”按钮,保存操作日志到数据库日志类usingMySqlConnector;usingSystem;usingSystem.Collections.Generic;usingSystem.Data;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceLog2{publicclassMyL......