最通俗易懂的sockfd用法解释

sockfd 是套接字(socket)类型,是文件描述符

1. sockfd 绑定的端口是谁的端口?

sockfd 是服务器创建的一个套接字描述符,它通过 bind() 函数绑定到一个特定的 IP 地址和端口号上。

  • 端口的概念:端口是一个标识特定应用程序或服务的数字。服务器程序绑定到一个端口上,以便客户端知道如何连接它。

  • 当服务器通过 sockfd 调用 bind() 绑定端口时,这个端口就是服务器的端口,它用于监听客户端的连接请求。客户端知道服务器的 IP 地址和端口号后,就可以向该端口发起连接。

所以,sockfd 绑定的是服务器的端口号,是服务器通过该端口接收客户端请求的入口。

2. sockfd如何监听,如何构建新连接?

当服务器使用 listen() 函数监听连接请求后,客户端会通过 connect() 函数向服务器发出请求。

  • 新连接指的是服务器接收到客户端的请求后,通过 accept() 函数创建一个新的套接字描述符。这个新的描述符专门用于处理与该特定客户端的通信。

  • 过程概述

    • 监听连接:服务器使用 listen() 监听来自客户端的连接请求。此时,sockfd 仍然只是监听套接字,用于等待连接请求。

    • 建立新连接:当有客户端请求连接时,accept() 会被调用,创建一个新的套接字(通常称为 clientfd),用于与这个特定客户端通信。

    • 多客户端连接:服务器可以同时处理多个客户端的请求。每个客户端连接请求都会生成一个新的套接字,用于处理与该客户端的通信。clientfd包含客户端的ip地址和端口号来区分

一个贴切的比喻

sockfd 像是迎宾员:负责站在门口(监听套接字,绑定了服务器的端口),等待客人(客户端)来请求服务。

客户端连接:当客人(客户端)到达并提出需求时,迎宾员(sockfd)会把客人带到一个特定的服务员(clientfd),这个服务员专门处理该客人的需求(新连接)。

新连接的含义:每个客人(客户端)都会有自己的服务员(新的套接字 clientfd),他们之间可以单独交流,而迎宾员继续等待其他新客人。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    int sockfd;
    struct sockaddr_in server_addr; //配置服务器
    
    // 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    
    // 配置服务器地址结构
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY; // 接受任意地址的连接
    server_addr.sin_port = htons(8080); // 绑定端口 8080
    
    // 绑定套接字到端口
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    
    // 设置套接字为监听状态,最多接受 10 个待处理连接
    if (listen(sockfd, 10) < 0) {
        perror("listen failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    
    printf("Server is listening on port 8080...\n");
    
    // 后续代码用于接受连接和处理客户端请求
    // ...

    // 关闭套接字
    close(sockfd);
    return 0;
}

以下是我个人的一些问题,搜寻答案如下:

1. clientfdsockfd 是否都是 socket 类型?

是的,clientfdsockfd 都是套接字(socket)类型,它们都是文件描述符,都是通过 socket() 函数创建的。

  • sockfd 是服务器最初创建的套接字,用于监听客户端连接请求。

  • clientfd 是通过 accept() 函数为每个客户端创建的新的套接字,用于与该特定客户端进行通信。

虽然它们都是套接字,但它们的用途不同:

  • sockfd 负责监听连接。

  • clientfd 负责与客户端的具体数据交互。

2. clientfd端口sockfd 是否相同?

clientfdsockfd 端口相同,但它们的使用方式不同。

  • 服务器的 sockfd 绑定的端口是服务器端的端口,例如 80(HTTP)或 8080(自定义服务端口),它通过这个端口监听客户端连接。

  • accept() 被调用时,clientfd 会创建用于与客户端通信的套接字。此时,clientfd 仍然使用服务器的同一个端口,但同时它也记录了客户端的 IP 地址和客户端的临时端口号(由客户端动态分配),用于与该客户端的后续通信。

3. 客户端请求新连接也是通过客户端的端口吗?

是的,客户端通过它自己的端口发起连接请求。具体来说:

  • 当客户端使用 socket() 创建一个套接字并调用 connect() 连接服务器时,客户端的操作系统会自动为客户端分配一个临时的本地端口(通常是 49152 到 65535 之间的动态端口),用于和服务器通信。

  • 客户端使用这个临时端口来与服务器通信,而服务器则通过它的固定监听端口(比如 80 或 8080)接收客户端的请求。

03-18
### 关于 Socket 文件描述符 (sockfd) `sockfd` 是指 socket 文件描述符,它是用于标识网络套接字的一个整数值。在网络编程中,`sockfd` 类似于普通的文件描述符,但它专门用来处理网络通信。通过 `sockfd`,可以执行诸如绑定地址、监听连接请求、接受客户端连接以及发送和接收数据的操作。 #### 创建 Socket 文件描述符 在 Linux 和类 Unix 系统中,可以通过调用 `socket()` 函数来创建一个 socket 文件描述符。以下是其基本语法: ```c #include <sys/socket.h> int sockfd = socket(int domain, int type, int protocol); ``` - **domain**: 指定协议族(protocol family),例如 `AF_INET` 表示 IPv4 地址簇。 - **type**: 指定套接字类型,常见的有 `SOCK_STREAM`(面向连接的 TCP 套接字)和 `SOCK_DGRAM`(无连接的 UDP 套接字)。 - **protocol**: 通常设置为 0,表示使用默认协议[^4]。 如果成功创建,则返回一个新的 socket 文件描述符;否则返回 `-1` 并设置错误号。 #### 绑定与监听 一旦创建了 `sockfd`,服务器端需要将其绑定到特定的 IP 地址和端口号上,并进入监听状态等待客户机发起连接请求。这涉及两个函数:`bind()` 和 `listen()`。 ```c struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT_NUMBER); server_addr.sin_addr.s_addr = INADDR_ANY; if(bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr))<0){ perror("Error binding"); } // 开始监听传入连接 if(listen(sockfd, MAX_BACKLOG)<0){ perror("Listen failed"); } ``` 上述代码片段展示了如何配置并启动服务端监听模式。 #### 接受连接 对于服务器来说,在准备好之后还需要调用 `accept()` 来实际建立与客户的连接关系。此时会产生另一个新的文件描述符代表这次具体的对话过程。 ```c int client_fd = accept(sockfd, NULL, NULL); if(client_fd < 0){ perror("Accept error"); } else { printf("Client connected\n"); } ``` 这里产生的 `client_fd` 就是用来同单一客户交互的具体通道。 #### 数据传输 无论是作为客户端还是服务端,都可以利用标准 I/O 函数如 `send()`, `recv()`, `write()`, 或者 `read()` 对应的数据操作来进行消息交换。 ```c char buffer[BUFFER_SIZE]; ssize_t bytes_received = recv(client_fd, buffer, BUFFER_SIZE - 1 , 0); if(bytes_received > 0){ buffer[bytes_received] = '\0'; printf("Received message: %s",buffer); }else{ close(client_fd); } ``` 以上例子说明了怎样从已有的连接里获取信息。 ### 总结 Socket 文件描述符 (`sockfd`) 提供了一种机制让不同主机上的应用能够互相通讯。它们遵循 POSIX 标准定义的行为特性,并且在整个生命周期内都保持着一致性的管理方式——即通过简单的整数编号形式加以控制访问权限及资源分配等问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值