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

5天挑战网络编程 -DAY1(linux版)

📅 Day 1:网络编程初探 —— 搭建你的第一个TCP连接


🎯 今日目标

  • 理解网络分层模型(TCP/IP 四层模型)
  • 掌握 TCP 协议的基本工作原理
  • 理解字节序(大小端)及其转换函数
  • 掌握 TCP 套接字(socket)编程的基本流程
  • 实现一个简单的 TCP "回声+大写转换"服务器与客户端

🧠 第一部分:理论基础

📘 网络分层模型:TCP/IP 四层模型

层级名称功能描述典型协议
应用层Application提供网络服务,处理应用程序细节HTTP、FTP、DNS、SMTP
传输层Transport提供端到端通信,负责数据传输的可靠性TCP、UDP
网际层Internet处理IP地址、路由选择等网络逻辑IP、ICMP
网络接口层Network Interface处理物理网络传输,如以太网帧以太网、WIFI

📌 补充:OSI 七层模型是理论模型,实际使用的是 TCP/IP 四层模型。


📘 TCP vs UDP 简要对比

特性TCPUDP
连接性面向连接(需要建立连接)无连接(直接发送数据)
可靠性可靠(确认、重传、流量控制)不可靠(尽力而为)
速度慢,开销大快,开销小
数据边界无(流式数据)有(数据报)
应用场景Web、文件传输、邮件视频、语音、游戏直播

📘 套接字(Socket)是什么?

在 Linux 中,“一切皆文件”,Socket 是一种特殊的文件描述符(fd),用于网络通信。通过套接字,应用程序可以像读写文件一样进行网络数据传输。


📘 字节序(Byte Order)

  • 大端(Big Endian):高位字节存储在低地址位置
  • 小端(Little Endian):低位字节存储在低地址位置
  • 网络字节序:统一使用大端,确保跨平台数据一致性

🧠 第二部分:重点函数详解

TCP 套接字编程核心函数

函数功能参数详细说明返回值
int socket(int domain, int type, int protocol)创建套接字domain: 地址族(AF_INET);type: 套接字类型(SOCK_STREAM);protocol: 协议(0)成功返回套接字描述符,失败返回-1
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)绑定地址sockfd: 套接字描述符;addr: 地址结构体指针;addrlen: 地址结构体大小成功返回0,失败返回-1
int listen(int sockfd, int backlog)监听连接sockfd: 监听套接字;backlog: 连接队列最大长度成功返回0,失败返回-1
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)接受连接sockfd: 监听套接字;addr: 客户端地址结构体;addrlen: 地址结构体大小指针成功返回新的连接套接字,失败返回-1
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)客户端连接服务器sockfd: 客户端套接字;addr: 服务器地址结构体;addrlen: 地址结构体大小成功返回0,失败返回-1
ssize_t send(int sockfd, const void *buf, size_t len, int flags)发送数据sockfd: 连接套接字;buf: 发送缓冲区;len: 发送长度;flags: 发送标志成功返回发送字节数,失败返回-1
ssize_t recv(int sockfd, void *buf, size_t len, int flags)接收数据sockfd: 连接套接字;buf: 接收缓冲区;len: 缓冲区大小;flags: 接收标志成功返回接收字节数,连接关闭返回0,失败返回-1
int close(int fd)关闭套接字fd: 文件描述符(套接字)成功返回0,失败返回-1

字节序转换函数详解

函数名功能参数说明返回值
uint16_t htons(uint16_t hostshort)主机字节序转网络字节序(16位)hostshort:主机字节序的短整型网络字节序的短整型
uint32_t htonl(uint32_t hostlong)主机字节序转网络字节序(32位)hostlong:主机字节序的长整型网络字节序的长整型
uint16_t ntohs(uint16_t netshort)网络字节序转主机字节序(16位)netshort:网络字节序的短整型主机字节序的短整型
uint32_t ntohl(uint32_t netlong)网络字节序转主机字节序(32位)netlong:网络字节序的长整型主机字节序的长整型

🧱 TCP 服务器/客户端开发流程

🔧 TCP 服务器开发流程(框架)
1. 创建套接字 socket()
2. 绑定地址 bind()
3. 监听连接 listen()
4. 接受连接 accept()
5. 收发数据 send() / recv()
6. 关闭连接 close()
🔧 TCP 客户端开发流程(框架)
1. 创建套接字 socket()
2. 连接服务器 connect()
3. 收发数据 send() / recv()
4. 关闭连接 close()

💻 第三部分:动手实战 —— TCP 回声+大写转换服务器

🧩 功能说明

  • 客户端输入字符串,发送给服务器
  • 服务器将字符串转为大写,并返回给客户端
  • 客户端打印收到的结果

📁 文件结构

tcp_server.c
tcp_client.c

🖥️ tcp_server.c(服务器端)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>#define PORT 8888           // 服务器监听端口号
#define MAX_BUFFER 1024     // 缓冲区大小int main() {int server_fd, client_fd;                           // 服务器和客户端套接字描述符struct sockaddr_in server_addr, client_addr;        // 服务器和客户端地址结构体socklen_t client_len = sizeof(client_addr);         // 客户端地址结构体大小char buffer[MAX_BUFFER];                            // 数据缓冲区// 1. 创建套接字// 函数原型:int socket(int domain, int type, int protocol);// 参数说明://   domain: 地址族,AF_INET表示IPv4//   type: 套接字类型,SOCK_STREAM表示TCP流式套接字//   protocol: 协议,0表示使用默认协议// 返回值:成功返回套接字描述符,失败返回-1server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd == -1) {perror("socket failed");    // 打印错误信息exit(EXIT_FAILURE);         // 退出程序}// 2. 设置服务器地址结构memset(&server_addr, 0, sizeof(server_addr));       // 清零地址结构体server_addr.sin_family = AF_INET;                   // 设置地址族为IPv4server_addr.sin_addr.s_addr = INADDR_ANY;           // 绑定所有本地IP地址server_addr.sin_port = htons(PORT);                 // 设置端口号(网络字节序)// 3. 绑定地址// 函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);// 参数说明://   sockfd: 套接字描述符//   addr: 指向地址结构体的指针//   addrlen: 地址结构体的大小// 返回值:成功返回0,失败返回-1if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("bind failed");close(server_fd);           // 关闭套接字exit(EXIT_FAILURE);}// 4. 监听连接// 函数原型:int listen(int sockfd, int backlog);// 参数说明://   sockfd: 监听套接字描述符//   backlog: 等待连接队列的最大长度// 返回值:成功返回0,失败返回-1if (listen(server_fd, 5) == -1) {perror("listen failed");close(server_fd);exit(EXIT_FAILURE);}printf("服务器启动,监听端口 %d...\n", PORT);// 5. 接受客户端连接while (1) {// 函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);// 参数说明://   sockfd: 监听套接字//   addr: 用于存储客户端地址信息的结构体//   addrlen: 客户端地址结构体大小的指针// 返回值:成功返回新的连接套接字,失败返回-1client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);if (client_fd == -1) {perror("accept failed");continue;  // 继续等待下一个连接}printf("客户端连接成功: %s:%d\n", inet_ntoa(client_addr.sin_addr),    // 将网络地址转换为点分十进制字符串ntohs(client_addr.sin_port));       // 将网络字节序端口号转换为主机字节序// 6. 收发数据while (1) {// 函数原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);// 参数说明://   sockfd: 连接套接字//   buf: 接收数据的缓冲区//   len: 缓冲区大小//   flags: 接收标志,通常为0// 返回值:成功返回接收到的字节数,连接关闭返回0,出错返回-1int n = recv(client_fd, buffer, MAX_BUFFER, 0);if (n <= 0) break; // 客户端断开或出错buffer[n] = '\0';  // 添加字符串结束符printf("收到数据: %s", buffer);// 转为大写for (int i = 0; i < n; i++) {buffer[i] = toupper(buffer[i]);  // 将字符转换为大写}// 函数原型:ssize_t send(int sockfd, const void *buf, size_t len, int flags);// 参数说明://   sockfd: 连接套接字//   buf: 发送数据的缓冲区//   len: 发送数据的长度//   flags: 发送标志,通常为0// 返回值:成功返回发送的字节数,失败返回-1send(client_fd, buffer, n, 0); // 回传给客户端}close(client_fd);  // 关闭客户端连接printf("客户端断开连接\n");}close(server_fd);  // 关闭服务器监听套接字return 0;
}

🖥️ tcp_client.c(客户端)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>#define SERVER_IP "127.0.0.1"   // 服务器IP地址(本地回环地址)
#define PORT 8888               // 服务器端口号
#define MAX_BUFFER 1024         // 缓冲区大小int main() {int client_fd;                              // 客户端套接字描述符struct sockaddr_in server_addr;             // 服务器地址结构体char buffer[MAX_BUFFER];                    // 数据缓冲区// 1. 创建套接字// 函数原型:int socket(int domain, int type, int protocol);// 参数说明同服务器端client_fd = socket(AF_INET, SOCK_STREAM, 0);if (client_fd == -1) {perror("socket failed");exit(EXIT_FAILURE);}// 2. 设置服务器地址memset(&server_addr, 0, sizeof(server_addr));       // 清零地址结构体server_addr.sin_family = AF_INET;                   // IPv4地址族server_addr.sin_port = htons(PORT);                 // 端口号(网络字节序)server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); // 服务器IP地址// 3. 连接服务器// 函数原型:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);// 参数说明://   sockfd: 客户端套接字//   addr: 服务器地址结构体//   addrlen: 地址结构体大小// 返回值:成功返回0,失败返回-1if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("connect failed");close(client_fd);exit(EXIT_FAILURE);}printf("连接服务器成功!输入字符串,服务器将返回大写版本。\n");// 4. 收发数据while (1) {printf("请输入: ");fgets(buffer, MAX_BUFFER, stdin);  // 从标准输入读取一行数据if (strncmp(buffer, "exit", 4) == 0) break;  // 输入exit退出// 发送数据到服务器send(client_fd, buffer, strlen(buffer), 0);// 接收服务器返回的数据int n = recv(client_fd, buffer, MAX_BUFFER, 0);if (n <= 0) break;  // 服务器关闭或出错buffer[n] = '\0';   // 添加字符串结束符printf("服务器返回: %s", buffer);}close(client_fd);  // 关闭客户端套接字return 0;
}

🛠️ 第四部分:编译与运行

编译命令详解

# 编译服务器程序
gcc tcp_server.c -o server# 编译客户端程序
gcc tcp_client.c -o client

命令解释:

  • gcc: GNU C编译器
  • tcp_server.c: 源代码文件名
  • -o server: 指定输出可执行文件名为server
  • tcp_client.c: 客户端源代码文件名
  • -o client: 指定输出可执行文件名为client

运行方式

# 终端1:启动服务器
./server# 终端2:启动客户端
./client

🧪 第五部分:测试与验证

示例交互

客户端输入:

hello world

服务器输出:

客户端连接成功: 127.0.0.1:54321
收到数据: hello world

客户端输出:

服务器返回: HELLO WORLD

📌 总结

✅ 今天你学会了:

  • TCP/IP 四层网络模型的基本概念
  • TCP 协议的特点和应用场景
  • 字节序的概念及转换函数的使用
  • TCP 服务器与客户端开发的完整流程
  • 套接字编程中各个关键函数的详细用法
  • 编写并运行了一个 TCP 回声 + 大写转换服务器

🎯 明天我们将学习 UDP 协议,体验无连接的轻快通信方式!


📌 Tips:

  • 多动手敲代码,不要只看
  • 多用 man 命令查看函数文档(如 man socketman bind 等)
  • 服务器运行后,不要关闭终端,保持运行状态
  • 理解每个函数的参数含义,这是网络编程的基础

👉 点个赞和关注,更多知识不迷路!!明天见!Day 2 更精彩:UDP 无连接通信实战!

http://www.dtcms.com/a/314906.html

相关文章:

  • 二十年代深度立体匹配的进化与前沿综述
  • 咖啡参考基因组
  • 机器学习 入门——决策树分类
  • FreeRTOS源码分析四:时钟中断处理响应流程
  • 倒排索引:Elasticsearch 搜索背后的底层原理
  • 【C#】Blazor基本应用
  • ICCV2025 Tracking相关paper汇总和解读(19篇)
  • Matlab(2)
  • Maven配置,Idea集成Maven_依赖引入,Idea生成单元测试
  • 《AI Agent工程师(初级)》
  • ubuntu24.01安装odoo18
  • gdb print设置技巧,离线查看复杂结构体和数组变量内容,展开多层嵌套的结构体的方法
  • 【Docker安装】Ubuntu 24.04.2 LTS系统下安装Docker环境——指定APT源安装方式
  • C + +
  • 宝塔运维实战:CentOs7启动PHP7.4失败
  • 华为OD机考2025C卷 - 最小矩阵宽度(Java Python JS C++ C )
  • Linux下PXE服务器搭建
  • 嵌入式数据结构笔记(二):内存工具与链表操作
  • QT 如何实现enum与字符串的互转
  • Java基础学习(一):类名规范、返回值、注释、数据类型
  • 【QT】安装与配置
  • 应急响应复现
  • Java 课程,每天解读一个简单Java之正整数分解质因数
  • 字符集选择utf8mb4
  • android内存作假通杀补丁(4GB作假8GB)
  • 自动寻迹小车介绍、原理及应用场景
  • GoLand 项目从 0 到 1:第四天 —— 技术选型落地与方案设计
  • onnxruntime配置开启ACL加速Arm上的模型推理
  • 《Python 实用项目与工具制作指南》· 3.2 实战·开发密码管理器
  • 【教学类-52-17】20250803动物数独_空格尽量分散_只有一半关卡数(N宫格通用版3-10宫格)0图、1图、2图、6图、有答案、无答案 组合版24套