网络编程入门:socket通讯及一线程一请求实现

        该文章描述如何创建一个传统的阻塞IO(输入/输出)模型在TCP网络编程中的使用。调用(如acceptrecvsend)。

        TCP的客户端和服务端交互流程的示意图:

  • 创建套接字 (socket()):

    • socket(AF_INET, SOCK_STREAM, 0)`创建了一个 IPv4 的流套接字,用于 TCP 通信。

  • 初始化服务器地址结构 (sockaddr_in):

    • 设置协议族AF_INET(IPv4)。

    • 将地址设为INADDR_ANY,意味服务器会监听所有网络接口。

    • 将端口号设为 2000,使用htons函数确保端口号在网络字节序。

  • 绑定套接字 (bind()):

    • 将创建的套接字绑定到初始化的地址和端口上。

  • 监听连接 (listen()):

    • 开始监听网络上的连接请求,10代表可同时等待的最大连接请求数。

​
int main(){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(struct sockaddr_in));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(2000);
    
    if(-1 == bind(sockfd, (struct sockaddr*)&servaddr,sizeof(struct sockaddr ))){
        printf("bind failed:%s\n", strerror(errno));
        return -1;
    }
    listen(sockfd, 10);
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);
    memset(&clientaddr, 0, len);//len = sizeof(struct sockaddr_in)
    
    
  • 接受客户端连接。

  • 接收来自客户端的数据,并将接收到的数据条数打印出来。

#if 0 
    \\客户端连接并recv
    printf("accept , sockfd:%d\n", sockfd);
    int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len);
    printf("accept finshed, clientfd:%d\n", clientfd);
    char buffer[1024] = {0};
    int count = recv(clientfd, buffer, 1024, 0);
    printf("recv count:%d", count);
  • accept可以多次接收客户端链接,但加while循环只能接受来自同一客户端的数据,并接收到数据后将其回送,send给第一个连接的客户端。直到对方的套接字已经正常关闭了连接(recv返回0)。

    #elif 0
        \\第一个客户端连接并重复接受回帧(多个客户端连接会卡在第一个recv)
            printf("accept before, sockfd:%d\n", sockfd);
            int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len);
            printf("accept finshed, clientfd:%d\n", clientfd);
        while(1){
            char buffer[1024] = {0};
            int count = recv(clientfd, buffer, 1024, 0);
            if(count == 0){
                break;
            }
            printf("recv count:%d\n", count);
            send (clientfd, buffer, count, 0);
            printf("send buffer:%s\n", buffer);
            
        }
    一请求一线程的实现
  • 对于每个接入的客户端,创建一个新线程来处理通信。

  • 线程内部循环接收数据,并将接收到的数据发送回客户端。

  • getchar()等待,防止程序直接退出

    #else 
        /*每传入一个listen fd,为每个clientfd创建一个新的线程*/
        while(1){  
            printf("accept before, sockfd:%d\n", sockfd);
            int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len);
            if(clientfd == -1){
                printf("accept failed! error:%s\n", strerror(errno));
                continue;
            }
            
            printf("accept finished, clientfd: %d, IP: %s, PORT:%d\n", clientfd,inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
            pthread_t thid;
            pthread_create(&thid, NULL, client_thread, &clientfd); 
        }
    #endif  
        getchar();
        //close(clientfd);
        return 0;
    线程处理函数 (client_thread
  • 每个客户端连接都通过该函数在单独的线程中处理。

    void *client_thread(void *arg) {
        
        int clientfd = *(int *)arg;
        while (1) {
            char buffer[1024] = {0};
            int count = recv(clientfd, buffer, 1024, 0);
            if(count == 0){
                close(clientfd);
                return NULL;
            }
            printf("recv count:%d\n", count);
            send(clientfd, buffer, count, 0);//recv同时send
            printf("send buffer:%s\n", buffer);
        }
    ​
    }

文章参考与<零声教育>的C/C++linux服务期高级架构系统教程学习:   https://it.0voice.com/p/t_pc/course_pc_detail/camp_pro/course_2U9D57IzMfQsoiaMuokdvXYV11c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值