网络: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 服务)
相关推荐
王道长服务器 | 亚马逊云4 小时前
AWS CloudTrail:让每一次操作都“有迹可循”
服务器·网络·云计算·智能路由器·aws
Tony Bai4 小时前
【Go 网络编程全解】06 UDP 数据报编程:速度、不可靠与应用层弥补
开发语言·网络·后端·golang·udp
我只有一岁半4 小时前
java17中,使用原生url connection的方式去创建的http链接,使用的是http1.1还是2.0?
网络·网络协议·http
梦想成为光头强!4 小时前
手机在初次联网的底层流程-关于EPC信令附着
网络·5g
青衫码上行6 小时前
【从0开始学习Java | 第21篇】网络编程综合练习
java·网络·学习
Chicheng_MA6 小时前
IPQ5322 Wi-Fi 7 SoC 路由器方案介绍
网络·路由器·ipq
BingoGo6 小时前
PHP8.5 的新 URI 扩展
后端·php
EasyDSS7 小时前
超越“接收端”:解析视频推拉流EasyDSS在RTMP推流生态中的核心价值与中流砥柱作用
网络·音视频
小糖学代码7 小时前
网络:2.Socket编程UDP
网络·网络协议·udp