网络:TCP

1 TCP实现客户端和服务器的读和写

服务器端

cpp 复制代码
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define handle_error(cmd,result)if(result < 0){perror(cmd);return -1;}
void *read_from_server(void *arg)
{
    //使用recv接收客户端发送数据,打印到控制台
    char *read_buf = NULL;
    int client_fd = *(int *)arg;
    read_buf = malloc(sizeof(char)*1024);
    ssize_t count = 0;
    if(!read_buf)
    {
        perror("malloc server read_buf");
        return NULL;
    }
    //接收数据
    while(count = recv(client_fd,read_buf,1024,0))
    {
        if(count < 0)
        {
            perror("recv");
            return NULL;
        }
        fputs(read_buf,stdout);
    }
    printf("服务端请求关闭\n");
    free(read_buf);
    return NULL;
}
void *write_to_server(void *arg)
{
    //接收控制台输入的信息,写进去
    char *write_buf = NULL;
    int client_fd = *(int *)arg;
    write_buf = malloc(sizeof(char)*1024);
    ssize_t count = 0;
    if(!write_buf)
    {
        perror("malloc server write_buf");
        return NULL;
    }
    while(fgets(write_buf,1024,stdin) != NULL)
    {
        count = send(client_fd,write_buf,1024,0);
        if(count < 0)
        {
            perror("send");
            return NULL;
        }
    }
    printf("接收到控制台的关闭请求,不再写入,关闭连接\n");
    shutdown(client_fd,SHUT_WR);
    free(write_buf);
    return NULL;
}
int main()
{
    struct sockaddr_in server_addr,client_addr;
    pthread_t pid_read,pid_write;
    memset(&server_addr,0,sizeof(server_addr));
    memset(&client_addr,0,sizeof(client_addr));

    //网络编程流程
    //1、创建socket
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    handle_error("socket",sockfd);
    //2、主动连接服务端
    server_addr.sin_family = AF_INET;
    inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr.s_addr);
    server_addr.sin_port = htons(8888);
    int temp_result = connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
    handle_error("connect",temp_result);
    printf("连接上服务端%s %d\n",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port));
    //创建子线程用于收消息
    pthread_create(&pid_read,NULL,read_from_server,(void*)&sockfd);
    //创建子线程用于发消息 
    pthread_create(&pid_write,NULL,write_to_server,(void*)&sockfd); 
    //阻塞主线程
    pthread_join(pid_read,NULL);
    pthread_join(pid_write,NULL);
    printf("释放资源");
    close(sockfd);
    return 0;
}

客户端

cpp 复制代码
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define handle_error(cmd,result)if(result < 0){perror(cmd);return -1;}
void *read_from_server(void *arg)
{
    //使用recv接收客户端发送数据,打印到控制台
    char *read_buf = NULL;
    int client_fd = *(int *)arg;
    read_buf = malloc(sizeof(char)*1024);
    ssize_t count = 0;
    if(!read_buf)
    {
        perror("malloc server read_buf");
        return NULL;
    }
    //接收数据
    while(count = recv(client_fd,read_buf,1024,0))
    {
        if(count < 0)
        {
            perror("recv");
            return NULL;
        }
        fputs(read_buf,stdout);
    }
    printf("服务端请求关闭\n");
    free(read_buf);
    return NULL;
}
void *write_to_server(void *arg)
{
    //接收控制台输入的信息,写进去
    char *write_buf = NULL;
    int client_fd = *(int *)arg;
    write_buf = malloc(sizeof(char)*1024);
    ssize_t count = 0;
    if(!write_buf)
    {
        perror("malloc server write_buf");
        return NULL;
    }
    while(fgets(write_buf,1024,stdin) != NULL)
    {
        count = send(client_fd,write_buf,1024,0);
        if(count < 0)
        {
            perror("send");
            return NULL;
        }
    }
    printf("接收到控制台的关闭请求,不再写入,关闭连接\n");
    shutdown(client_fd,SHUT_WR);
    free(write_buf);
    return NULL;
}
int main()
{
    struct sockaddr_in server_addr,client_addr;
    pthread_t pid_read,pid_write;
    memset(&server_addr,0,sizeof(server_addr));
    memset(&client_addr,0,sizeof(client_addr));

    //网络编程流程
    //1、创建socket
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    handle_error("socket",sockfd);
    //2、主动连接服务端
    server_addr.sin_family = AF_INET;
    inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr.s_addr);
    server_addr.sin_port = htons(8888);
    int temp_result = connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
    handle_error("connect",temp_result);
    printf("连接上服务端%s %d\n",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port));
    //创建子线程用于收消息
    pthread_create(&pid_read,NULL,read_from_server,(void*)&sockfd);
    //创建子线程用于发消息 
    pthread_create(&pid_write,NULL,write_to_server,(void*)&sockfd); 
    //阻塞主线程
    pthread_join(pid_read,NULL);
    pthread_join(pid_write,NULL);
    printf("释放资源");
    close(sockfd);
    return 0;
}

sudo netstat -tanlp

这个指令可以监控TCP运行情况

sudo apt install wireshark

这个指令用来安装可视化查看网络连接app,下载好之后不要直接打开,通过指令打开:

sudo wireshark

2 TCP实现多连接客户端与服务器端

服务器端

cpp 复制代码
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define handle_error(cmd,result)if(result < 0){perror(cmd);return -1;}

void*read_from_client_write(void *arg)
{
    //读取客户端发送过来的数据 回复收到
    int client_fd = *(int *)arg;
    char *read_buf = NULL;
    char *write_buf = NULL;
    ssize_t count = 0,send_count = 0;

    read_buf = malloc(sizeof(char)*1024);
    write_buf = malloc(sizeof(char)*1024);

    if(!read_buf)
    {
        printf("初始化读缓冲失败\n");
        close(client_fd);
        perror("read_buf");
        return NULL;
    }
    if(!write_buf)
    {
        printf("初始化写缓冲失败\n");
        close(client_fd);
        perror("write_buf");
        return NULL;
    }
    while(count = recv(client_fd,read_buf,1024,0))
    {
        if(count < 0)
        {
            perror("recv");
            return NULL;
        }
        //接收数据打印到控制台
        printf("从%d客户端收到数据%s\n",client_fd,read_buf);
        //把收到的数据写入到写缓冲器中
        strcpy(write_buf,"收到\n");
        send_count = send(client_fd,write_buf,1024,0);
        if(send_count < 0)
        {
            perror("send");
            return NULL;
        }
    }
    //当客户端输入ctrl+d结束循环
    close(client_fd);
    free(read_buf);
    free(write_buf);
}
int main()
{
    struct sockaddr_in server_addr,client_addr;

    memset(&server_addr,0,sizeof(server_addr));
    memset(&client_addr,0,sizeof(client_addr));
    //填写服务端地址
    server_addr.sin_family = AF_INET;
    //填写ip地址0.0.0.0
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //第二种ip地址写法:inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr.s_addr);
    //填写端口号
    server_addr.sin_port = htons(8888);
    //网络编程流程
    //1、socket
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    handle_error("socket",sockfd);
    //2、绑定地址
    int temp_result = bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
    handle_error("bind",temp_result);
    //3、进入监听状态
    temp_result = listen(sockfd,80);
    handle_error("bind",temp_result);
    //4、获取客户端的连接,返回的文件描述符才是能够和客户端收发消息的
    //需要能够接收多个连接
    socklen_t cliaddr_len = sizeof(client_addr);
    while(1)
    {
        pthread_t pid_read_write;
        int clientfd = accept(sockfd,(struct sockaddr*)&client_addr,&cliaddr_len);
        handle_error("accept",clientfd);
        printf("与客户端%s %d 建立连接\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
        //和每一个客户端使用一个线程交互 把客户端发送的信息打印到控制台 回复收到
        if(pthread_create(&pid_read_write,NULL,read_from_client_write,(void*)&clientfd))
        {
            perror("pthread_create");
            return 1;
        }
        //需要等待线程结束,但是不能挂起
        pthread_detach(pid_read_write);
    }
    printf("释放资源\n");
    close(sockfd);
    return 0;
}

客户端

cpp 复制代码
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define handle_error(cmd,result)if(result < 0){perror(cmd);return -1;}
void *read_from_server(void *arg)
{
    //使用recv接收服务端发送数据,打印到控制台
    char *read_buf = NULL;
    int client_fd = *(int *)arg;
    read_buf = malloc(sizeof(char)*1024);
    ssize_t count = 0;
    if(!read_buf)
    {
        perror("malloc server read_buf");
        return NULL;
    }
    //接收数据
    while(count = recv(client_fd,read_buf,1024,0))
    {
        if(count < 0)
        {
            perror("recv");
            return NULL;
        }
        fputs(read_buf,stdout);
    }
    printf("服务端请求关闭\n");
    free(read_buf);
    return NULL;
}
void *write_to_server(void *arg)
{
    //接收控制台输入的信息,写进去
    char *write_buf = NULL;
    int client_fd = *(int *)arg;
    write_buf = malloc(sizeof(char)*1024);
    ssize_t count = 0;
    if(!write_buf)
    {
        perror("malloc server write_buf");
        return NULL;
    }
    while(fgets(write_buf,1024,stdin) != NULL)
    {
        count = send(client_fd,write_buf,1024,0);
        if(count < 0)
        {
            perror("send");
            return NULL;
        }
    }
    printf("接收到控制台的关闭请求,不再写入,关闭连接\n");
    shutdown(client_fd,SHUT_WR);
    free(write_buf);
    return NULL;
}
int main()
{
    struct sockaddr_in server_addr,client_addr;
    pthread_t pid_read,pid_write;
    memset(&server_addr,0,sizeof(server_addr));
    memset(&client_addr,0,sizeof(client_addr));

    //网络编程流程
    //1、创建socket
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    handle_error("socket",sockfd);
    //2、主动连接服务端
    server_addr.sin_family = AF_INET;
    inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr.s_addr);
    server_addr.sin_port = htons(8888);
    int temp_result = connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
    handle_error("connect",temp_result);
    printf("连接上服务端%s %d\n",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port));
    //创建子线程用于收消息
    pthread_create(&pid_read,NULL,read_from_server,(void*)&sockfd);
    //创建子线程用于发消息 
    pthread_create(&pid_write,NULL,write_to_server,(void*)&sockfd); 
    //阻塞主线程
    pthread_join(pid_read,NULL);
    pthread_join(pid_write,NULL);
    printf("释放资源");
    close(sockfd);
    return 0;
}
相关推荐
女神下凡16 分钟前
芯参谋(107):杰理AC_中科蓝讯_开发指南
linux·服务器·网络·单片机·嵌入式硬件
爱和冰阔落5 小时前
【Linux网络】TCP 半包粘包怎么解决?从长度报头、JSON 拆包到网络计算器完整实战
linux·运维·网络·tcp/ip
say_fall7 小时前
【Linux网络编程】UDP套接字编程:系统编程组件、基础回显服务、InetAddr与地址转换、翻译服务与线程池聊天室
linux·服务器·网络·udp·vr
我不会插花弄玉19 小时前
6.传输层协议UDP【由浅入深-网络】
网络·网络协议·udp
火云代理20 小时前
更换网络后为什么会退出登录?分清 IP、Cookie 与会话的关系
服务器·网络·网络协议·tcp/ip·php·ip
xbzb1 天前
容器 IP 每次重建都变?docker network 五种模式与自定义网桥固定地址
网络·docker·容器·ip·network·固定
火云代理1 天前
同一个网站,有的网络能打开、有的打不开?认识 IPv4 与 IPv6 的访问差异
服务器·网络·网络协议·tcp/ip·测试工具·php·状态模式
坤坤子吖1 天前
Linux网络编程:TCP 粘包与半包问题,如何正确处理 TCP 流式数据?
linux·服务器·网络·笔记·网络协议·学习
火云代理1 天前
Python 使用代理 IP 前,先弄清 Requests 的配置来源与验证方法
网络·python·网络协议·tcp/ip·ip
如夏倾城1 天前
QUIC——HTTP/3 的唯一底层传输协议 及 0-RTT恢复
网络·网络协议·tcp/ip·安全·http