当前位置:首页 > 行业动态 > 正文

C语言中TCP API的使用与实现详解,你掌握了吗?

TCP API 是用于网络通信的编程接口,支持基于传输控制协议(TCP)的数据交互。

C语言中的TCP API

C语言中TCP API的使用与实现详解,你掌握了吗?  第1张

在网络编程中,传输控制协议(TCP)是一种面向连接的、可靠的传输层通信协议,C语言提供了一组广泛的API,用于实现基于TCP的网络通信,这些API通常被称为套接字(socket)API,它们为开发者提供了创建和管理网络连接的能力,本文将详细介绍C语言中常用的TCP相关API,并以表格形式展示关键信息。

关键TCP API及说明

函数名 描述 参数列表 返回值
socket() 创建一个套接字。 int socket(int domain, int type, int protocol);

domain: 地址族(如AF_INET)。

type: 套接字类型(如SOCK_STREAM)。

protocol: 协议(通常为0)。

成功返回套接字描述符,失败返回-1。
bind() 绑定套接字到指定IP地址和端口。 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockfd: 套接字文件描述符。

addr: 指向sockaddr结构体的指针,包含地址和端口信息。

addrlen: 地址结构体的长度。

成功返回0,失败返回-1。
listen() 设置套接字为监听模式,准备接受连接。 int listen(int sockfd, int backlog);

sockfd: 套接字文件描述符。

backlog: 请求队列的最大长度。

成功返回0,失败返回-1。
accept() 接受一个连接请求,并返回一个新的套接字。 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd: 监听套接字文件描述符。

addr: 指向存储客户端地址的结构体。

addrlen: 地址结构体的长度。

成功返回新套接字描述符,失败返回-1。
connect() 向服务器发起连接请求。 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockfd: 套接字文件描述符。

addr: 指向存储服务器地址的结构体。

addrlen: 地址结构体的长度。

成功返回0,失败返回-1。
send() 通过套接字发送数据。 ssize_t send(int sockfd, const void *buf, size_t len, int flags);

sockfd: 套接字文件描述符。

buf: 数据缓冲区。

len: 缓冲区长度。

flags: 标志位(通常为0)。

成功返回实际发送的字节数,失败返回-1。
recv() 接收来自套接字的数据。 ssize_t recv(int sockfd, void *buf, size_t len, int flags);

sockfd: 套接字文件描述符。

buf: 数据缓冲区。

len: 缓冲区长度。

flags: 标志位(通常为0)。

成功返回实际接收的字节数,失败返回-1。
close() 关闭套接字。 int close(int sockfd);

sockfd: 套接字文件描述符。

成功返回0,失败返回-1。
shutdown() 关闭套接字的部分或全部通道。 int shutdown(int sockfd, int how);

sockfd: 套接字文件描述符。

how: 关闭方式(如SHUT_RD、SHUT_WR、SHUT_RDWR)。

成功返回0,失败返回-1。

示例代码

以下是一个简单的C语言TCP客户端和服务器的示例代码:

服务器端代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
      
    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
      
    // Forcefully attaching socket to the port 8080
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
      
    // Forcefully attaching socket to the port 8080
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
      
    char buffer[1024] = {0};
    int valread = read( new_socket , buffer, 1024);
    printf("%s
",buffer );
    send(new_socket , "Hello from server" , strlen("Hello from server") , 0 );
    printf("Hello message sent
");
    return 0;
}

客户端代码:

#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[]) {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char const *hello = "Hello from client";
    char buffer[1024] = {0};
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("
 Socket creation error 
");
        return -1;
    }
      
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);
      
    // Convert IPv4 and IPv6 addresses from text to binary form
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {
        printf("
Invalid address/ Address not supported 
");
        return -1;
    }
      
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("
Connection Failed 
");
        return -1;
    }
    send(sock, hello, strlen(hello), 0 );
    printf("Hello message sent
");
    int valread = read( sock, buffer, 1024);
    printf("%s
",buffer );
    return 0;
}

常见问题FAQs

Q1: 如何选择合适的TCP端口号?

A1: TCP端口号范围从0到65535,其中0到1023是知名端口,需要管理员权限;1024到49151是注册端口,通常由应用程序使用;49152到65535是动态或私有端口,可供临时使用。

Q2: 如何处理TCP连接中的超时问题?

A2: 可以使用setsockopt()函数设置套接字选项来处理超时问题,可以设置接收超时和发送超时。

Q3: TCP三次握手的具体过程是什么?

A3: 第一次握手:客户端发送SYN包到服务器,进入SYN_SENT状态,第二次握手:服务器收到SYN包后,回复SYN+ACK包,进入SYN_RECEIVED状态,第三次握手:客户端收到服务器的SYN+ACK包后,回复一个ACK包,进入ESTABLISHED状态,连接建立完成。

0