当前位置: 首页 > 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.lryc.cn/news/602962.html

相关文章:

  • STM32 USB HOST 驱动FT232 USB转串
  • 安装anaconda后,如何进入python解释器
  • SSH 远程控制及相关工具
  • 常见的JVM虚拟机的参数详解
  • “量子通信”
  • 【C语言网络编程基础】TCP并发网络编程:io多路复用
  • 五自由度磁悬浮轴承转子:基于自适应陷波器的零振动攻克不平衡质量扰动的终极策略
  • linux du、df命令使用教程
  • 面向对象设计原则和设计模式分类
  • 开源AI智能体-JoyAgent集成Deepseek
  • C++模板元编程从入门到精通
  • [论文阅读] 人工智能 | 机器学习工作流的“救星”:数据虚拟化服务如何解决数据管理难题?
  • [机缘参悟-236]:通过AI人工神经网络理解人的思维特征:惯性思维、路径依赖、适应性、不同场合不同言行、经验、概率、常规与特殊情形(正态分布)、环境适应性
  • 5 分钟上手 Firecrawl
  • Java项目:基于SSM框架实现的社区团购管理系统【ssm+B/S架构+源码+数据库+毕业论文+答辩PPT+远程部署】
  • js的学习1
  • 如何理解有符号数在计算机中用​​补码​​存储
  • 阿里给AI To C战略戴上眼镜
  • 案例开发 - 日程管理 - 第三期
  • Android Handler 完全指南
  • 【QT搭建opencv环境】
  • 商城系统-项目测试
  • redis未授权getshell四种方式
  • Ubuntu24安装MariaDB/MySQL后不知道root密码如何解决
  • 基于STM32设计的智慧果园云监测系统_256
  • 基于Uniapp及Spring Boot的奢侈品二手交易平台的设计与实现/基于微信小程序的二手交易系统
  • linux安装zsh,oh-my-zsh,配置zsh主题及插件的方法
  • 机器学习基础-numpy
  • OpenMP 并行编程核心机制详解:从变量作用域到同步优化
  • SwinTransformer改进(14):集成MLCA注意力机制的Swin Transformer模型