零基础入门嵌入式Linux网络编程:C常用函数解析与示例代码

本章函数大全

目录

本章函数大全

1. 网络编程基本流程

2. 关键函数解析

2.1 socket() - 创建套接字

2.2 bind() - 绑定IP和端口(仅服务器端)

2.3 listen() - 监听连接请求(仅服务器端)

2.4 accept() - 接收客户端连接(仅服务器端)

2.5 connect() - 连接服务器(仅客户端)

2.6 recv() & send() - 数据传输

2.7 shutdown() & close() - 关闭连接

3. 服务器 & 客户端示例代码

服务器代码

客户端代码

4. 结论

参考链接


在网络编程中,了解并掌握 socketbindlistenacceptconnectrecvsendshutdownclose 这些函数至关重要。本文将逐一解析它们的作用,并提供相应的示例代码和总结表格,帮助你快速掌握这些关键函数。


1. 网络编程基本流程

网络编程通常涉及以下步骤:

  • 服务器端

    1. 创建 socket
    2. 绑定 bind
    3. 监听 listen
    4. 接收连接 accept
    5. 进行数据通信 (recv/send)
    6. 关闭连接 (shutdown/close)
  • 客户端

    1. 创建 socket(绑定bind可有可无)
    2. 连接 connect
    3. 进行数据通信 (recv/send)
    4. 关闭连接 (shutdown/close)

2. 关键函数解析

2.1 socket() - 创建套接字

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
  • domain: 地址协议族,如 AF_INET (IPv4) 或 AF_INET6 (IPv6)。
  • type: 套接字类型,如 SOCK_STREAM (TCP) 或 SOCK_DGRAM (UDP)。
  • protocol: 通常为 0,表示使用默认协议。
  • 返回值: 成功返回套接字文件描述符,失败返回 -1

示例代码:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
    perror("socket creation failed");
    exit(EXIT_FAILURE);
}

2.2 bind() - 绑定IP和端口(仅服务器端)

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd: 由 socket() 创建的套接字文件描述符。
  • addr: 指向 sockaddr 结构体的指针,包含IP和端口信息。
  • addrlen: addr 结构体的大小。
  • 返回值: 成功返回 0,失败返回 -1

示例代码:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;

if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
    perror("bind failed");
    exit(EXIT_FAILURE);
}

2.3 listen() - 监听连接请求(仅服务器端)

int listen(int sockfd, int backlog);
  • sockfd: 服务器的监听套接字。
  • backlog: 队列中最大连接数。
  • 返回值: 成功返回 0,失败返回 -1

示例代码:

if (listen(sockfd, 5) == -1) {
    perror("listen failed");
    exit(EXIT_FAILURE);
}

2.4 accept() - 接收客户端连接(仅服务器端)

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

示例代码:

struct sockaddr_in client_addr;
socklen_t addr_size = sizeof(client_addr);
int client_sock = accept(sockfd, (struct sockaddr*)&client_addr, &addr_size);
if (client_sock == -1) {
    perror("accept failed");
    exit(EXIT_FAILURE);
}

2.5 connect() - 连接服务器(仅客户端)

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

示例代码:

if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
    perror("connect failed");
    exit(EXIT_FAILURE);
}

2.6 recv() & send() - 数据传输

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

示例代码:

char buffer[1024];
int bytes_received = recv(client_sock, buffer, sizeof(buffer), 0);
if (bytes_received > 0) {
    printf("Received: %s\n", buffer);
}

2.7 shutdown() & close() - 关闭连接

int shutdown(int sockfd, int how);
int close(int sockfd);

示例代码:

shutdown(client_sock, SHUT_WR);
close(client_sock);

3. 服务器 & 客户端示例代码

服务器代码

// server.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SOCKET_DOMAIN   AF_INET             // (域名)网络层端点协议:ipv4
#define SOCKET_TYPE     SOCK_STREAM         // 传输层协议:TCP
#define SERVER_SOCKADDR "127.0.0.1"         // 设置服务端地址
#define SERVER_SOCKPORT 8888                // 设置服务端端口号
#define BACKLOG         5                   // 如果连接数超过 BACKLOG 新连接请求将被拒绝(或延迟处理)
#define MAXLENGTH       256                 // 最大字节长度

#define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

static void *read_from_client(void *arg)
{
    int fd = *(int *)arg;
    char *rbuf = calloc(MAXLENGTH+1,sizeof(char));
    if(rbuf == NULL){
        perror("calloc");
        return NULL;
    }
    ssize_t rbytes = 0;
    // flag=0:阻塞等待数据
    while((rbytes = recv(fd, rbuf, MAXLENGTH+1, 0)) > 0){
        printf("%.*s",(int)rbytes,rbuf);
    }
    if(rbytes == -1){
        perror("recv");
    }
    printf("客户端请求关闭\n");
    free(rbuf);
    return NULL;
}

static void *write_to_client(void *arg)
{
    int fd = *(int *)arg;
    char *wbuf = calloc(MAXLENGTH+1,sizeof(char));
    if(wbuf == NULL){
        perror("calloc");
        return NULL;
    }
    while(fgets(wbuf,MAXLENGTH,stdin)){
        wbuf[MAXLENGTH] = 0;
        if(send(fd,wbuf,strlen(wbuf),0) == -1){
            perror("send");
            break;
        }
    }
    printf("服务端接收到控制台的关闭请求,不再写入,开始挥手\n");
    shutdown(fd, SHUT_WR);
    free(wbuf);
    return NULL;
}

int main(int argc,char *argv[])
{
    int sockfd,clientfd;
    struct sockaddr_in client_sockaddr;
    socklen_t client_sockaddr_len = sizeof(client_sockaddr);
    // 服务端地址和端口初始化
    struct sockaddr_in server_sockaddr;
    memset(&server_sockaddr, 0, sizeof(server_sockaddr));
    server_sockaddr.sin_family  = SOCKET_DOMAIN;
    inet_pton(SOCKET_DOMAIN, SERVER_SOCKADDR, &server_sockaddr.sin_addr);
    // server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_sockaddr.sin_port = htons(SERVER_SOCKPORT);

    pthread_t pthread_read;
    pthread_t pthread_write;

    // 客户端网络编程流程
    // 1.为通信创建端点
    sockfd = socket(SOCKET_DOMAIN,SOCKET_TYPE,0);
    if(sockfd == -1)
        handle_error("socket");
    printf("服务端文件描述符:%d\n",sockfd);
    // 2.创建好客户端地址结构,绑定
    if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr)) < 0){
        close(sockfd);
        handle_error("bind");
    }
    
    // 3.监听
    if(listen(sockfd, BACKLOG) == -1){
        close(sockfd);
        handle_error("listen");
    }
    printf("正在监听端口: %d\n",SERVER_SOCKPORT);

    //4.阻塞等待连接
    clientfd = accept(sockfd, (struct sockaddr *)&client_sockaddr,&client_sockaddr_len);
    if(clientfd == -1){
        close(sockfd);
        handle_error("accept");
    }
    printf("有客户端进行连接: %s %d 文件描述符:%d\n",inet_ntoa(client_sockaddr.sin_addr),ntohs(client_sockaddr.sin_port),clientfd);

    // 4.创建本地接收和发送数据线程
    pthread_create(&pthread_read,NULL,read_from_client,(void *)&clientfd);
    pthread_create(&pthread_write,NULL,write_to_client,(void *)&clientfd);

    // 5.阻塞主线程
    pthread_join(pthread_read,NULL);
    pthread_join(pthread_write,NULL);

    printf("服务端断开连接,释放资源\n");
    close(clientfd);
    close(sockfd);
    return 0;
}

客户端代码

// client.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SOCKET_DOMAIN   AF_INET             // (域名)网络层端点协议:ipv4
#define SOCKET_TYPE     SOCK_STREAM         // 传输层协议:TCP
#define CLIENT_SOCKADDR "172.xxx.xxx.xxx" 这里填写自己的ip地址   // 设置本地地址
#define CLIENT_SOCKPORT 6666                // 设置本地端口号
#define SERVER_SOCKADDR "127.0.0.1"         // 设置服务端地址
#define SERVER_SOCKPORT 8888                // 设置服务端端口号
#define MAXLENGTH       256                 // 最大字节长度

#define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

static void *read_from_server(void *arg)
{
    int fd = *(int *)arg;
    char *rbuf = calloc(MAXLENGTH+1,sizeof(char));
    if(rbuf == NULL){
        perror("calloc");
        return NULL;
    }
    ssize_t rbytes = 0;
    // flag=0:阻塞等待数据
    while((rbytes = recv(fd, rbuf, MAXLENGTH+1, 0)) > 0){
        printf("%.*s",(int)rbytes,rbuf);
    }
    if(rbytes == -1){
        perror("recv");
    }
    printf("服务端请求关闭\n");
    free(rbuf);
    return NULL;
}

static void *write_to_server(void *arg)
{
    int fd = *(int *)arg;
    char *wbuf = calloc(MAXLENGTH+1,sizeof(char));
    if(wbuf == NULL){
        perror("calloc");
        return NULL;
    }
    while(fgets(wbuf,MAXLENGTH,stdin)){
        wbuf[MAXLENGTH] = 0;
        if(send(fd,wbuf,strlen(wbuf),0) == -1){
            perror("send");
            break;
        }
    }
    printf("客户端接收到控制台的关闭请求,不再写入,开始挥手\n");
    shutdown(fd, SHUT_WR);
    free(wbuf);
    return NULL;
}

int main(int argc,char *argv[])
{
    int sockfd;
    // 客户端地址和端口初始化
    struct sockaddr_in client_sockaddr;
    memset(&client_sockaddr, 0, sizeof(client_sockaddr));
    client_sockaddr.sin_family  = SOCKET_DOMAIN;
    inet_pton(SOCKET_DOMAIN, CLIENT_SOCKADDR, &client_sockaddr.sin_addr);
    client_sockaddr.sin_port = htons(CLIENT_SOCKPORT);

    // 服务端地址和端口初始化
    struct sockaddr_in server_sockaddr;
    memset(&server_sockaddr, 0, sizeof(server_sockaddr));
    server_sockaddr.sin_family  = SOCKET_DOMAIN;
    inet_pton(SOCKET_DOMAIN, SERVER_SOCKADDR, &server_sockaddr.sin_addr);
    server_sockaddr.sin_port = htons(SERVER_SOCKPORT);

    pthread_t pthread_read;
    pthread_t pthread_write;

    // 客户端网络编程流程
    // 1.为通信创建端点
    sockfd = socket(SOCKET_DOMAIN,SOCKET_TYPE,0);
    if(sockfd == -1)
        handle_error("socket");
    printf("客户端文件描述符:%d\n",sockfd);
    // 2.创建好客户端地址结构,绑定/可有可无
    // if(bind(sockfd,(struct sockaddr *)&client_sockaddr,sizeof(client_sockaddr)) < 0){
    //     close(sockfd);
    //     handle_error("bind");
    // }
    
    // 3.创建好服务器地址结构,连接服务端
    if(connect(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr)) < 0){
        close(sockfd);
        handle_error("connect");
    }
    printf("连接上服务器 %s %d\n",inet_ntoa(server_sockaddr.sin_addr),ntohs(server_sockaddr.sin_port));

    // 4.创建本地接收和发送数据线程
    pthread_create(&pthread_read,NULL,read_from_server,(void *)&sockfd);
    pthread_create(&pthread_write,NULL,write_to_server,(void *)&sockfd);

    // 5.阻塞主线程
    pthread_join(pthread_read,NULL);
    pthread_join(pthread_write,NULL);

    printf("客户端断开连接,释放资源\n");
    close(sockfd);
    return 0;
}

注:示例程序为本地作为服务端与本地进行通信


4. 结论

函数作用
socket创建套接字
bind绑定地址
listen监听连接
accept接受连接
connect连接服务器
recv/send传输数据
shutdown关闭连接
close关闭套接字

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

银河码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值