【C/C++】网络编程入门

【C/C++】网络编程入门


本文基于一请求一线程框架,实现一个服务器与多个客户端连接,彼此互不影响

函数介绍

  • socket:创建文件描述符 fd
  • bind:服务端绑定端口,绑定失败返回 -1
  • listen:服务端开始监听
  • accept:服务端接受客户端连接,未接受到则阻塞,返回文件描述符 fd
  • recv:服务端接受客户端发送数据,保存到 buffer 缓冲区,未接受到则阻塞,返回实际接收到数据的字节数,客户端断开返回0
  • send:服务端从buffer中取出数据发送到客户端
  • close:关闭文件描述符

过程描述

  1. 服务器启动,创建 sockfd,阻塞在 accept 位置,等待客户端连接
  2. 客户端连接服务器,创建 clientfd,pthread_create 创建线程,阻塞在 recv 位置
  3. 客户端主动发送消息,该线程完成一个 while 循环,继续阻塞在 recv 位置
  4. 客户端退出连接,此时 recv 返回 0,关闭 clientfd,跳出循环,线程结束
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>

void* client_thread(void* arg) {
    int clientfd = *(int *)arg;
    while (1) {
        char buffer[1024] = {0};
        int count = recv(clientfd, buffer, sizeof(buffer), 0);
        if (count == 0) {
            close(clientfd);
            printf("client %d disconnected\n", clientfd);
            break;
        }
        printf("RECV %s\n", buffer);
        send(clientfd, buffer, count, 0);
        printf("SEND %d\n", count);
    }
}

int main(void) {
    //服务端
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(2000);
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (struct sockaddr *) &serveraddr, sizeof (struct sockaddr)) == -1) {
        printf("bind error %d", sockfd);
        return -1;
    }
    listen(sockfd, 10);
    printf("listening... %d\n", sockfd);

    //客户端
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof (struct sockaddr);
    while (1) {
        printf("accepting...\n");
        int clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);
        printf("client %d accepted\n", clientfd);
        pthread_t tid;
        pthread_create(&tid, NULL, client_thread, &clientfd);
    }

    return 0;
}

常见问题

  • 出现 bind error,通过 netstat -an | grep 2000,发现连接处于 TIME_WAIT,此时上一次连接强制断开,稍等片刻重连即可
    在这里插入图片描述

总结


  1. 服务端和客户端连接需要分别创建一个 sockfd 和 clientfd,clientfd 的生命周期与该客户端连接的生命周期一致
  2. 每有一个客户端就会新建一个 clientfd,该方法相当于一个线程管理一个 clientfd,在后续客户端数量很多的时候性能低下
  3. 后续优化可以从单线程管理多个 clientfd,优化 fd 的管理模式上进行

技术参考

推荐一个零声教育学习教程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值