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

计算机网络编程-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.xdnf.cn/news/16398.html

相关文章:

  • 企业级JWT验证最佳方案:StringUtils.hasText()
  • 使用Ettus USRP X440对雷达和EW系统进行原型验证
  • 分布式IO选型指南:2025年分布式无线远程IO品牌及采集控制方案详解
  • Python动态规划:从基础到高阶优化的全面指南(2)
  • socketpair函数详解
  • Qt小组件 - 8 图片浏览器
  • go‑cdc‑chunkers:用 CDC 实现智能分块 强力去重
  • SpringBoot轻松集成豆包AI
  • 精简 RT-Thread 工程并查找占用空间大的模块
  • 中国汽车能源消耗量(2010-2024年)
  • java里List链式编程
  • 【智慧物联网平台】安装部署教程——仙盟创梦IDE
  • Jenkins流水线部署+webhook2.0
  • 四、计算机组成原理——第7章:输入/输出系统
  • 命令执行漏洞
  • EAP(基于事件的异步编程模式)
  • 思途SQL学习 0728
  • SIM2REAL记录
  • 初识 docker [下] 项目部署
  • 亚马逊地址关联暴雷:新算法下的账号安全保卫战
  • 通过具有一致性嵌入的大语言模型(LMMs)实现端到端乳腺癌放射治疗计划制定|文献速递-医学影像算法文献分享
  • 反欺诈系统:Oracle 到 ES 迁移实战
  • 形参表不匹配(BUG)
  • R语言常用扩展包
  • 【自动化运维神器Ansible】Ansible常用模块之unarchive模块详解
  • YOLO11 改进、魔改|低分辨率自注意力机制LRSA ,提取全局上下文建模与局部细节,提升小目标、密集小目标的检测能力
  • 10、Docker Compose 安装 MySQL
  • 动/静态库的原理及制作
  • 鸿蒙打包签名
  • Linux:线程同步与线程互斥