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

3. Socket 编程 TCP

1. TCP网络程序

socket 常用 API

socket()

socket只负责获取链接 - listensockfd

socket()打开一个网络通讯端口,如果成功的话,就像 open()一样返回一个文件描
述符;
应用程序可以像读写文件一样用 read/write 在网络上收发数据
如果 socket()调用出错则返回-1;
对于 TCP 协议,type 参数指定为 SOCK_STREAM, 表示面向流的传输协议

bind()

服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服
务器程序的地址和端口号后就可以向服务器发起连接; 服务器需要调用 bind 绑定一
个固定的网络地址和端口号;

bind()的作用是将参数 sockfd myaddr 绑定在一起, 使 sockfd 这个用于网络通讯的文件描述符监听 myaddr 所描述的地址和端口号;
struct sockaddr *是一个通用指针类型,myaddr 参数实际上可以接受多种协议的 sockaddr 结构体,而它们的长度各不相同,所以需要第三个参数 addrlen 指定结构体的长度;
我们的程序中对 myaddr 参数是这样初始化的:

 1. 将整个结构体清零;

 2. 设置地址类型为 AF_INET;

 3. 网络地址为 INADDR_ANY, 这个宏表示本地的任意 IP 地址,因为服务器可能有
多个网卡,每个网卡也可能绑定多个 IP 地址, 这样设置可以在所有的 IP 地址上监听,
直到与某个客户端建立了连接时才确定下来到底用哪个 IP 地址;
 4. 端口号为 SERV_PORT,我们定义为9999;

listen()

listen()声明 sockfd 处于监听状态, 并且最多允许有 backlog 个客户端处于连接等待状态, 如果接收到更多的连接请求就忽略, 这里设置不会太大(一般是 5),
listen()成功返回 0,失败返回-1;

accept()

accept获得的链接,在哪里?从内核中直接获取,建立连接的过程与accept无关

accept返回值,就是给我们提供服务 - 读写,即IO服务

三次握手完成后, 服务器调用 accept()接受连接;
如果服务器调用 accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来;
addr 是一个传出参数,accept()返回时传出客户端的地址和端口号;
如果给 addr 参数传 NULL,表示不关心客户端的地址;
addrlen 参数是一个传入传出参数(value-result argument), 传入的是调用者提供的, 缓冲区 addr的长度以避免缓冲区溢出问题, 传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区);

我们的服务器程序结构是这样的:

while (1) {cliaddr_len = sizeof(cliaddr);connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len);n = read(connfd, buf, MAXLINE);close(connfd);
}

 客户端需要调用 connect()连接服务器;

connect 和 bind 的参数形式一致, 区别在于 bind 的参数是自己的地址, 而connect 的参数是对方的地址;
connect()成功返回 0,出错返回-1
结论:只要tcp服务器处于listen状态,那么他就已经可以被连接了!!
因为:
a. tcp是全双工
b. 客户端和服务器在一台机器上(主要原因)

2. V1 - Echo Server(线程池版本)

问题1:进程如果退出了,曾经打开的文件会怎么办?默认会自动释放覅掉,fd,会自动被关close(fd)

问题2:进程如果打开了一个文件,得到了一个fd,如果再创建子进程,这个子进程能拿到父进程的fd进行访问吗? -- 能,管道不就是吗

Command.hpp

问题1:如果进程打开了一个文件,得到了一个fd,这个fd线程能看到吗?(能)

问题2:线程敢不敢关闭自己不需要的fd?(不敢) 

1. 文件描述符的内核共享机制

2. 如果多个线程同时操作同一个 fd(例如通过全局变量或参数传递),关闭操作可能导致竞态条件

3. 在多线程服务器中,子线程不应关闭监听套接字(通常由主线程维护)

Common.hpp

Cond.hpp

Dict.hpp

dictionary.txt

InetAddr.hpp

Log.hpp

makefile

Mutex.hpp

TcpClient.cc

由于客户端不需要固定的端口号,因此不必调用 bind(),客户端的端口号由内核自动分配

 客户端不是不允许调用 bind(), 只是没有必要显示的调用 bind()固定一个端口 号. 否则如果在同一台机器上启动多个客户端, 就会出现端口号被占用导致不能正确建立连接;

服务器也不是必须调用 bind(), 但如果服务器不调用 bind(), 内核会自动给服务 器分配监听端口, 每次启动服务器时端口号都不一样, 客户端要连接服务器就会遇到麻烦。

测试多个

TcpServer.cc

TcpServer.hpp

Thread.hpp

ThreadPool.hpp

附录:

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

相关文章:

  • 广播,数据库01 day43
  • JVM垃圾收集算法和垃圾收集器
  • 阿里云通义灵码深度解析:AI编程时代的技术革命与实践探索
  • 基于Hadoop3.3.4+Flink1.17.0+FlinkCDC3.0.0+Iceberg1.5.0整合,实现数仓实时同步mysql数据
  • 如何在 Ubuntu 24.04 或 22.04 Linux 上安装和使用 NoMachine
  • python导包机制-更优方式
  • 新华三H3CNE网络工程师认证—Telnet
  • 《 服务注册发现原理:从 Eureka 到 Nacos 的演进》
  • 7、Docker 常用命令大全
  • Python + Requests库爬取动态Ajax分页数据
  • Qt:盒子模型的理解
  • WebSocket双向通信——引入进行功能优化
  • opencv学习(轮廓检测)
  • ACL 访问控制列表全解析:从规则语法到实战配置
  • 旧物回收小程序:科技赋能,让旧物回收焕发生机
  • Avalonia的自定义边框窗口
  • React中为甚么强调props的不可变性
  • TMS320F2812PGFA TI:150MHz工业级DSP控制芯片,电机控制专用
  • 腾讯AI IDE
  • 天学网面试 —— 中级前端开发岗位
  • 动/静态库的原理及制作
  • 测试用例设计常用方法
  • MR-link-2:多效性顺式孟德尔随机化分析!
  • Windows 系统分辨率切换** 与 **Qt4 无边框窗口管理机制** 的交互
  • 2025年7月21–28日AI开发周报:新模型、新战略与开源亮点
  • 全新AI工具小程序源码 全开源
  • 北京-4年功能测试2年空窗-报培训班学测开-第六十二天-模拟未通过,继续准备自我介绍项目介绍面试题中
  • java中一些数据结构的转换
  • C++模板元编程从入门到精通
  • 从“PPT动画”到“丝滑如德芙”——uni-app x 动画性能的“终极奥义”