网络:3.Socket编程TCP

Socket编程TCP

一.接口补充

1. listen(系统调用)

作用:
将一个主动套接字(客户端用的 socket)转换为被动套接字,使其可以接受来自客户端的连接请求。(常用于 TCP 服务器端,UDP 无需调用该函数)

函数原型

cpp 复制代码
#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd, int backlog);
  • 参数

    • sockfd:TCP 套接字文件描述符;
    • backlog:未完成连接队列(半连接队列) 的最大长度;表示允许系统为该监听 socket 同时排队的最大连接请求数;超过该值的连接请求将被丢弃;
  • 返回值

    • 成功: 0
    • 失败: -1,并设置 errno

2. accept(系统调用)

作用:从已完成连接队列中取出一个已建立的客户端连接,生成一个新的套接字用于与该客户端通信 (常用于 TCP 服务器端;UDP 无连接,不需要调用此函数).

函数原型

cpp 复制代码
#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//没有连接就会阻塞卡在这里
  • 参数

    • sockfd:服务器端用于监听的套接字文件描述符(必须已调用bind和listen);
    • addr(输出型参数):
      • 指向一个 struct sockaddr_in 结构体的指针,用于保存已连接客户端的地址信息(IP + 端口);
      • 若不关心客户端地址,可填 NULL。
    • addrlen(输出型参数):
      • 指向一个 socklen_t 类型变量的指针,初始时应设置为 sizeof(struct sockaddr_in);
      • 函数返回时,会被修改为实际的地址结构长度。
  • 返回值

    • 成功: 返回一个新的套接字文件描述符(用于与客户端通信);
    • 失败: 返回 -1,并设置errno。

3. connect(系统调用)

作用: 用于客户端向服务器发起连接请求; 当服务器端调用了 listen() 并处于监听状态后,客户端使用 connect() 来建立 TCP 连接(三次握手);(常用于 TCP 客户端;UDP 客户端也可调用该函数以指定默认通信目标地址.)

函数原型

cpp 复制代码
#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数

    • sockfd:套接字文件描述符;
      • 通常是:socket(AF_INET, SOCK_STREAM, 0)(TCP);
      • 对于 UDP(SOCK_DGRAM),调用 connect 并不会真正建立连接,而是指定默认的目标地址。
    • addr: 指向服务器端地址结构体的指针(struct sockaddr_in server; 使用时需强制类型转换为 struct sockaddr*);
    • addrlen:地址结构体的大小,sizeof(struct sockaddr_in)。
  • 返回值

    • 成功: 0
    • 失败: -1,并设置 errno
  • 注:

    client会在connect成功之后,在底层自动进行bind!


4. popen(库函数)

作用:
创建一个管道,与一个子进程之间建立单向通信通道,并通过该子进程执行指定的命令(通常是 shell 命令)。

它相当于同时调用了 fork() + pipe() + exec(),让父进程可以像读写文件一样与命令交互。

函数原型

cpp 复制代码
#include <stdio.h>

FILE *popen(const char *command, const char *type);
  • 参数

    • **command:**要执行的 shell 命令字符串,例如 "ls -l", "cat /etc/passwd" 等;
      • 实际上会调用 /bin/sh -c command 来执行;
      • 因此几乎所有命令行都可以写在这里。
    • type: 打开管道的模式
      • "r":从命令的标准输出(stdout) 读取数据(父进程读,子进程写);一般用这个
      • "w":向命令的标准输入(stdin) 写入数据(父进程写,子进程读)。
  • 返回值

    • 成功: 返回一个 FILE* 类型的文件流指针;
    • 失败: 返回 NULL,并设置 errno。
  • 注意事项

    管道使用完毕后,必须调用:

    cpp 复制代码
    int pclose(FILE *stream);

    来关闭管道并等待子进程结束(否则会产生僵尸进程)。

二.命令补充

1. telnet

作用:用于测试服务器端口是否可连通、是否在监听, 常用于验证TCP服务是否正常工作, 它通过建立 TCP 连接的方式模拟客户端访问。

命令格式

shell 复制代码
telnet [主机名或IP地址] [端口号]
  • 返回结果说明
情况 输出提示 含义
成功连接 Connected to xxx.xxx.xxx.xxx 说明端口已开放且可通信
连接失败 Connection refused 端口未被监听或被防火墙拦截**
超时 Connection timed out 网络不可达 / 服务器无响应
未解析 Unknown host 域名错误或 DNS 无法解析
  • 按下:Ctrl + ], 回车,开始输入
  • 然后输入:quit,退出
  • 或再按下Ctrl + ], 回车,退出。

三.知识补充

1. TCP 服务器中 listen 和 accept 的分工关系:

  • listen 的socket(_listensockfd) :
    就像"店员张三在门口拉客",只负责等待并接受新的连接请求 (即负责"拉人进来")。
    它本身不提供服务,不进行读写操作。
  • accept 返回的新socket(sockfd) :
    就像张三把客人带进来后,交给店里的人(李四、王五、赵六)去"提供具体服务"。
    每个客户端连接都会生成一个新的 socket,用于 读写数据(I/O 服务)。
相关推荐
Web极客码17 分钟前
我用 Claude 分析 Redis 哨兵日志,实现跨机房数据不一致自动对齐
数据库·redis·php
xuefeiniao1 小时前
PHP2Shell漏洞修复
运维·服务器·php
ServBay2 小时前
AI说代码没漏洞?马上被 PHP 打脸了
aigc·php·ai编程
g3voip3 小时前
工业防水电话到底怎么选?隧道、管廊与码头的需求差异
服务器·网络·信息与通信·ip
珠海西格电力3 小时前
零碳园区管理系统的性能评估体系的行业标准
大数据·网络·人工智能·物联网·机器学习·架构·能源
tq10864 小时前
对PHP漏洞的思考
php
wangruofeng4 小时前
黑色十月:AI 找到的漏洞,两小时数十万次利用
人工智能·安全·php
.Bryce.4 小时前
从强化学习到Agentic RL:让Agent在“干活“中自己变聪明
服务器·网络·agent·rag·agentic rl
NetInside_4 小时前
Unknown,不应该是网络分析的终点
网络
码少女4 小时前
Linux——UDP协议和TCP协议
linux·网络·udp·tcp