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

相关文章:

  • python:讲懂决策树,为理解随机森林算法做准备,以示例带学习,通俗易懂,容易理解和掌握
  • 句子表征-文本匹配--representation-based/interactive-based
  • 学习日志27 python
  • 基于开源AI智能名片链动2+1模式与S2B2C商城小程序的直播营销销量转化机制研究
  • 短剧小程序系统开发:引领影视消费新潮流
  • 【世纪龙科技】汽车自动变速器拆装虚拟实训软件
  • 音视频文案字幕一键提取,免费使用,效率软件!
  • AR远程协作网页设计:虚实融合场景下的故障标注与操作指引界面
  • AR技术赋能轨道交通培训:虚实结合提升学习效率
  • AUTOSAR AR-Explorer正式发布
  • 6s081环境配置以及使用vscode连接本地wsl2
  • Qt 使用QtXlsx库处理Excel文件
  • AR技术赋能能源勘探:从数据可视化到智能预测的革命性突破
  • 《解构Angular组件变化检测:从自动到手 动的效能突破》
  • 【Git 误操作恢复指南】
  • 如何安装 nvm-setup.exe?Windows 安装 NVM 管理 Node.js 版本的完整流程(附安装包下载)
  • 配置Mybatis环境
  • ollama解锁LLM生成上下文长度
  • 墨者学院SQL过滤字符后手工绕过漏洞测试(万能口令)
  • Lifelong Learning and Selective Forgetting via Contrastive Strategy
  • 深度学习图像处理篇之AlexNet模型详解
  • docker镜像源配置教程,以及解决安装好docker配置镜像源后,出现报错。Job for docker.service failed
  • 洛谷做题11:P1424 小鱼的航程(改进版)
  • Android Espresso 测试框架深度解析:从入门到精通
  • GCC与AI:编译优化新革命
  • PHP进阶语法详解:命名空间、类型转换与文件操作
  • 第二十四天(数据结构:栈和队列)队列实践请看下一篇
  • 进一步分析云手机的优势有哪些?
  • 论文Review LIO Multi-session Voxel-SLAM | 港大MARS出品!体素+平面特征的激光SLAM!经典必读!
  • JAVA,springAOP