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

计算机网络编程-Socket通信以及实战

1 Socket基本原理

套接字(Socket)学习

2 代码实战

server.c

// 引入必要的头文件
#include <stdio.h>      // 标准输入输出(printf、perror等)
#include <stdlib.h>     // 标准库(exit函数)
#include <string.h>     // 字符串处理(memset、strlen等)
#include <unistd.h>     // 系统调用(close、read、write等)
#include <sys/socket.h> // socket核心函数(socket、bind、listen等)
#include <netinet/in.h> // 网络地址结构(sockaddr_in等)#define PORT 8080               // 服务器端口号(1024-65535之间,避免冲突)
#define BUFFER_SIZE 1024        // 数据缓冲区大小int main() {// 1. 定义变量int server_fd;               // 服务器socket文件描述符(类似句柄)int new_socket;              // 客户端连接的socket文件描述符struct sockaddr_in address;  // 存储服务器和客户端的地址信息int opt = 1;                 // setsockopt的选项值int addrlen = sizeof(address); // 地址结构的长度char buffer[BUFFER_SIZE] = {0}; // 数据缓冲区,初始化全为0const char *hello = "Hello from server"; // 服务器发送的消息// 2. 创建socket// 参数1:AF_INET → 使用IPv4协议// 参数2:SOCK_STREAM → 面向连接的TCP协议// 参数3:0 → 自动选择协议(此处为IPPROTO_TCP)if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed"); // 出错时打印错误信息(perror会自动添加原因)exit(EXIT_FAILURE);      // 退出程序,返回失败状态}// 3. 设置socket选项(可选但推荐)// SOL_SOCKET:设置socket层面的选项// SO_REUSEADDR:允许端口被重复使用(避免服务器重启时"地址已在使用"错误)// SO_REUSEPORT:允许多个socket绑定到同一端口(需系统支持)if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {perror("setsockopt");exit(EXIT_FAILURE);}// 4. 初始化地址结构address.sin_family = AF_INET;         // 使用IPv4address.sin_addr.s_addr = INADDR_ANY; // 绑定到所有可用的本地IP(0.0.0.0)address.sin_port = htons(PORT);       // 端口号转换为网络字节序(大端序)// htons:host to network short(主机字节序→网络字节序)// 5. 绑定socket到指定地址和端口// 参数1:服务器socket的文件描述符// 参数2:通用地址结构指针(需强制转换)// 参数3:地址结构长度if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// 6. 监听连接(使socket进入被动模式)// 参数2:backlog → 最大等待连接队列长度(超过则新连接被拒绝)if (listen(server_fd, 3) < 0) { // 允许最多3个连接在队列中等待perror("listen");exit(EXIT_FAILURE);}printf("Server listening on port %d...\n", PORT);// 7. 接受客户端连接(阻塞等待,直到有客户端连接)// 返回一个新的socket文件描述符(用于与该客户端通信)if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}printf("Client connected: %s:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));// inet_ntoa:将网络字节序的IP地址转换为字符串(如192.168.1.1)// ntohs:network to host short(网络字节序→主机字节序)// 8. 读取客户端发送的数据ssize_t valread = read(new_socket, buffer, BUFFER_SIZE); // read返回实际读取的字节数(<= BUFFER_SIZE),0表示客户端关闭连接,-1表示错误printf("Received from client: %s\n", buffer);// 9. 向客户端发送响应send(new_socket, hello, strlen(hello), 0); // send参数:socket、数据、长度、标志(0表示默认)printf("Hello message sent\n");// 10. 关闭连接(释放资源)close(new_socket);  // 关闭与客户端的连接close(server_fd);   // 关闭服务器socketprintf("Server closed\n");return 0;
}

client.c

// 引入必要的头文件(与服务器相同)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>  // 额外包含:inet_addr函数(IP地址转换)#define PORT 8080               // 服务器端口号(需与服务器一致)
#define BUFFER_SIZE 1024        // 数据缓冲区大小int main(int argc, char const *argv[]) {// 1. 定义变量int sock = 0;                // 客户端socket文件描述符struct sockaddr_in serv_addr; // 服务器地址结构char buffer[BUFFER_SIZE] = {0}; // 数据缓冲区const char *hello = "Hello from client"; // 客户端发送的消息// 2. 创建socket(与服务器相同)if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket creation error");exit(EXIT_FAILURE);}// 3. 初始化服务器地址结构memset(&serv_addr, '0', sizeof(serv_addr)); // 清空地址结构serv_addr.sin_family = AF_INET;             // IPv4serv_addr.sin_port = htons(PORT);           // 服务器端口(网络字节序)// 4. 转换服务器IP地址(字符串→网络字节序)// 若服务器在本地,可使用"127.0.0.1";若在远程,替换为实际IPif (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {// inet_pton:将点分十进制IP转换为网络字节序(支持IPv6,比inet_addr更推荐)perror("invalid address/address not supported");exit(EXIT_FAILURE);}// 5. 连接服务器(触发TCP三次握手)if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("connection failed");exit(EXIT_FAILURE);}printf("Connected to server\n");// 6. 向服务器发送数据send(sock, hello, strlen(hello), 0);printf("Hello message sent\n");// 7. 读取服务器的响应ssize_t valread = read(sock, buffer, BUFFER_SIZE);printf("Received from server: %s\n", buffer);// 8. 关闭socketclose(sock);printf("Client closed\n");return 0;
}
http://www.dtcms.com/a/303171.html

相关文章:

  • Ettus USRP X410/X440 运行 ADC 自校准
  • Yolo底层原理学习--(第二篇)
  • STM32-基本定时器
  • 【动态规划 | 路径问题】动态规划方法:解决路径问题的最佳策略
  • ESP32-S3学习笔记<8>:LEDC的应用
  • 【历史人物】【韩愈】简历与生平
  • Springboot 项目中使用 Filter 全指南
  • 基于Python的arXiv论文数据分析系统:从爬取到可视化的完整实践
  • flexbuild-imx91 imx93
  • Java-分布式锁
  • Lakehouse: Unifying DW Advanced Analytics in Open Platforms
  • 【C语言网络编程基础】TCP并发网络编程:io多路复用
  • 开源赋能产业,生态共筑未来 | 开源科学计算与系统建模(openSCS)分论坛圆满举行
  • 笔试——Day21
  • JS面试题
  • Linux 远程连接与文件传输:从基础到高级配置
  • QT之QThread 与 QtConcurrent
  • 【自动化运维神器Ansible】Ansible常用模块之cron模块详解
  • GaussDB as的用法
  • 【GaussDB】内存资源告急:深度诊断一起“memory temporarily unavailable“故障
  • DMETL安装流程及简单使用
  • OpenLayers 入门指南【四】:项目初始化
  • Qt小组件 - 8 图片浏览器
  • MySQL高级配置与优化实战指南
  • 利用 SQL Server 实现字符替换的高效函数
  • 第二十一天(shell练习)
  • IT运维的365天--033 跨交换机部署没有单独供电口的爱快AP到另一个地方去
  • 如何选择适合高并发环境的服务器:性能与稳定性的平衡
  • 短剧小程序系统开发:连接创作者与用户的桥梁
  • Node.js + TypeScript 开发健壮的淘宝商品 API SDK