5. Network programming - related applications of TCP

Table of contents

1. Use TCP to implement two programs chatting with each other (with receiving and sending operations)

1. Server

2. Client

2. Realize that multiple users connect to the server, and the server can send messages to specified users

1. Server

2. Client

1. Use TCP to implement two programs chatting with each other (with receiving and sending operations)

1. Server

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>  // 包含了地址结构体的定义声明
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>


void * send_msg (void * arg)
{
    int connect_fd = *(int *)arg ;

    // 发送
    char * msg = calloc(128,1);
    while(1)
    {
        bzero(msg , 128 );
        fgets(msg , 128 , stdin);
        int ret_val =  send(connect_fd , msg , strlen(msg) , 0 );
        if ( ret_val != -1 )
        {
            printf("send msg succeed : %d byte \n" , ret_val );
        }
        else{
            perror("send error !!");
        }
    }

} 


int main(int argc, char const *argv[])
{
    // 创建一个套接字 (购买一台手机)
    int sock_fd = socket( AF_INET , SOCK_STREAM , 0 ); // 使用IPV4协议簇, 流式套接字(TCP)
    if (-1 == sock_fd)
    {
        perror("socket rror");
        return -1 ;
    }
    

    // 配置自己的IP和端口号等信息
    // struct sockaddr_in   // IPV4地址结构体
    // {
    //     u_short sin_family;// 地址族
    //     u_short sin_port;// 端口
    //     struct in_addr sin_addr;// IPV4 地址
    //     char sin_zero[8];
    // };
    int addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in my_addr = {
        .sin_addr.s_addr = htonl(INADDR_ANY) , // 设置服务器的地址, INADDR_ANY 指本机中任何一个地址
        .sin_family = AF_INET , // 使用 IPV4 协议簇
        .sin_port = htons(65000) // 设置服务器的端口号为  65000 
    };

    // 绑定地址信息 (IP + 端口号 + 协议簇)
    int ret_val =  bind(  sock_fd,  (struct sockaddr *)&my_addr, addrlen);
    if (ret_val == -1 )
    {
        perror("bind error");
        return -1 ;
    }else{
        printf(" bind succeed !!\n") ;
    }
    
    // 设置监听 (打开铃声)
    if(listen( sock_fd,  5 )) // 设置sock_fd 为监听套接字, 同时可以接收连接请求数为  5 + 4(默认值) 
    {
        perror("listen error");
        return -1 ;
    }

    // 等待连接
    struct sockaddr_in from_addr; 
    int connect_fd = accept( sock_fd , (struct sockaddr *)&from_addr, &addrlen);
    if (connect_fd == -1 )
    {
        perror("connect error");
        return -1 ;
    }
    else{
        printf("connect succeed !!\n");
    }
    
    // 创建一个接发送数据的线程
    pthread_t thread ;
    pthread_create( &thread, NULL ,send_msg , (void*)&connect_fd  ); // 参数把已连接套接字进行传递

    // 聊天
    char * msg = calloc(128,1);
    while(1)
    {
        bzero(msg , 128 );
        ret_val =  recv(connect_fd , msg , 128 , 0 );// 阻塞接收对方发来的消息
        if ( ret_val != -1 )
        {
            printf("recv msg : %s " , msg );
        }
        else{
            perror("recv error !!");
        }
    }

    // 关闭套接字
    close(sock_fd);
    

    return 0;
}

2. Client

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>  // 包含了地址结构体的定义声明
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>


void * send_msg (void * arg)
{
    int connect_fd = *(int *)arg ;

    // 发送
    char * msg = calloc(128,1);
    while(1)
    {
        bzero(msg , 128 );
        fgets(msg , 128 , stdin);
        int ret_val =  send(connect_fd , msg , strlen(msg) , 0 );
        if ( ret_val != -1 )
        {
            printf("send msg succeed : %d byte \n" , ret_val );
        }
        else{
            perror("send error !!");
        }
    }

} 


int main(int argc, char const *argv[])
{
    // 创建一个套接字 (购买一台手机)
    int sock_fd = socket( AF_INET , SOCK_STREAM , 0 ); // 使用IPV4协议簇, 流式套接字(TCP)
    if (-1 == sock_fd)
    {
        perror("socket rror");
        return -1 ;
    }
    

    // 配置自己的IP和端口号等信息
    // struct sockaddr_in   // IPV4地址结构体
    // {
    //     u_short sin_family;// 地址族
    //     u_short sin_port;// 端口
    //     struct in_addr sin_addr;// IPV4 地址
    //     char sin_zero[8];
    // };
    int addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in server_addr = {
        .sin_addr.s_addr = inet_addr("192.168.102.2") , // 设置服务器的地址
        .sin_family = AF_INET , // 使用 IPV4 协议簇
        .sin_port = htons(65000) // 设置服务器的端口号为  65000 
    };

  
    // 连接服务器
    if( connect(sock_fd , (const struct sockaddr *)&server_addr, addrlen))
    {
        perror("connect error");
        return -1 ;
    }

    // 创建一个接发送数据的线程
    pthread_t thread ;
    pthread_create( &thread, NULL ,send_msg , (void*)&sock_fd  ); // 参数把已连接套接字进行传递

    
    // 聊天
    char * msg = calloc(128,1);
    int ret_val = -1 ;
    while(1)
    {
        bzero(msg , 128 );
        ret_val =  recv(sock_fd , msg , 128 , 0 );// 阻塞接收对方发来的消息
        if ( ret_val != -1 )
        {
            printf("recv msg : %s " , msg );
        }
        else{
            perror("recv error !!");
        }
    }


    // 关闭套接字
    close(sock_fd);
    

    return 0;
}

2. Realize that multiple users connect to the server, and the server can send messages to specified users

1. Server

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>  // 包含了地址结构体的定义声明
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>

int num = 0 ; // 数组下标
int  connect_arr [10] ;

void * send_msg (void * arg)
{
    // 发送
    char * msg = calloc(128,1);
    while(1)
    {
        printf("请输入 # 查看当前在线用户并 选择发送对象:\n");

        while(getchar() != '#');

        printf("**********************************************\n");
        
        for (int i = 0; i < num ; i++)
        {
            printf("%d 在线用户编号:%d\n" , i , connect_arr[i] );
        }
        
        printf("*************请输入需要回信的编号***************\n");
        int i ; 
        scanf("%d" , &i);
        while(getchar() != '\n');


        bzero(msg , 128 );
        fgets(msg , 128 , stdin);
        int ret_val =  send(connect_arr[i] , msg , strlen(msg) , 0 );
        if ( ret_val != -1 )
        {
            printf("send msg succeed : %d byte \n" , ret_val );
        }
        else{
            perror("send error !!");
        }
    }
} 

void * recv_msg (void * arg)
{
    // 把传过来的描述符转换并保存
    int connect_fd = *(int *)arg ;

    // 聊天
    char * msg = calloc(128,1);
    int ret_val = -1 ;
    while(1)
    {
        bzero(msg , 128 );
        ret_val =  recv(connect_fd , msg , 128 , 0 );// 阻塞接收对方发来的消息
        if ( ret_val != -1 )
        {
            printf("recv msg from %d client : %s " , connect_fd ,  msg );
        }
        else{
            perror("recv error !!");
        }
    }
}

int main(int argc, char const *argv[])
{
    // 创建一个套接字 (购买一台手机)
    int sock_fd = socket( AF_INET , SOCK_STREAM , 0 ); // 使用IPV4协议簇, 流式套接字(TCP)
    if (-1 == sock_fd)
    {
        perror("socket rror");
        return -1 ;
    }
    

    // 配置自己的IP和端口号等信息
    // struct sockaddr_in   // IPV4地址结构体
    // {
    //     u_short sin_family;// 地址族
    //     u_short sin_port;// 端口
    //     struct in_addr sin_addr;// IPV4 地址
    //     char sin_zero[8];
    // };
    int addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in my_addr = {
        .sin_addr.s_addr = htonl(INADDR_ANY) , // 设置服务器的地址, INADDR_ANY 指本机中任何一个地址
        .sin_family = AF_INET , // 使用 IPV4 协议簇
        .sin_port = htons(65000) // 设置服务器的端口号为  65000 
    };

    // 绑定地址信息 (IP + 端口号 + 协议簇)
    int ret_val =  bind(  sock_fd,  (struct sockaddr *)&my_addr, addrlen);
    if (ret_val == -1 )
    {
        perror("bind error");
        return -1 ;
    }else{
        printf(" bind succeed !!\n") ;
    }
    
    // 设置监听 (打开铃声)
    if(listen( sock_fd,  5 )) // 设置sock_fd 为监听套接字, 同时可以接收连接请求数为  5 + 4(默认值) 
    {
        perror("listen error");
        return -1 ;
    }

    // 创建一个接发送数据的线程
    pthread_t thread ;
    pthread_create( &thread, NULL ,send_msg , NULL ); // 参数把已连接套接字进行传递

    int connect_fd;
    pthread_t thread1 ;
    
    while(1)
    {
        // 等待连接
        struct sockaddr_in from_addr; 
        connect_fd = accept( sock_fd , (struct sockaddr *)&from_addr, &addrlen);
        if (connect_fd == -1 )
        {
            perror("connect error");
            return -1 ;
        }
        else{
            if(num >= 9 )
            {
                break ;
            }
            printf("connect succeed !!\n");
            // 为该用户创建一个线程专门用来接收他发来的消息
            pthread_create( &thread1, NULL , recv_msg , (void*)&connect_fd ); // 参数把已连接套接字进行传递
            connect_arr[num] = connect_fd;
            num ++ ;
        }
    }

    // 等待线程退出
    pthread_join(thread , NULL) ;

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

2. Client

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>  // 包含了地址结构体的定义声明
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>


void * send_msg (void * arg)
{
    int connect_fd = *(int *)arg ;

    // 发送
    char * msg = calloc(128,1);
    while(1)
    {
        bzero(msg , 128 );
        fgets(msg , 128 , stdin);
        int ret_val =  send(connect_fd , msg , strlen(msg) , 0 );
        if ( ret_val != -1 )
        {
            printf("send msg succeed : %d byte \n" , ret_val );
        }
        else{
            perror("send error !!");
        }
    }

} 


int main(int argc, char const *argv[])
{
    // 创建一个套接字 (购买一台手机)
    int sock_fd = socket( AF_INET , SOCK_STREAM , 0 ); // 使用IPV4协议簇, 流式套接字(TCP)
    if (-1 == sock_fd)
    {
        perror("socket rror");
        return -1 ;
    }
    

    // 配置自己的IP和端口号等信息
    // struct sockaddr_in   // IPV4地址结构体
    // {
    //     u_short sin_family;// 地址族
    //     u_short sin_port;// 端口
    //     struct in_addr sin_addr;// IPV4 地址
    //     char sin_zero[8];
    // };
    int addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in server_addr = {
        .sin_addr.s_addr = inet_addr("192.168.102.2") , // 设置服务器的地址
        .sin_family = AF_INET , // 使用 IPV4 协议簇
        .sin_port = htons(65000) // 设置服务器的端口号为  65000 
    };

  
    // 连接服务器
    if( connect(sock_fd , (const struct sockaddr *)&server_addr, addrlen))
    {
        perror("connect error");
        return -1 ;
    }

    // 创建一个接发送数据的线程
    pthread_t thread ;
    pthread_create( &thread, NULL ,send_msg , (void*)&sock_fd  ); // 参数把已连接套接字进行传递

    
    // 聊天
    char * msg = calloc(128,1);
    int ret_val = -1 ;
    while(1)
    {
        bzero(msg , 128 );
        ret_val =  recv(sock_fd , msg , 128 , 0 );// 阻塞接收对方发来的消息
        if ( ret_val != -1 )
        {
            printf("recv msg : %s " , msg );
        }
        else{
            perror("recv error !!");
        }
    }


    // 关闭套接字
    close(sock_fd);
    

    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45981798/article/details/129911435