网络: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;
}
相关推荐
b55t4ck27 分钟前
Draytek vigo3910 工业路由器固件解密及其CVE-2024-23721漏洞分析
网络·物联网·网络安全
日取其半万世不竭1 小时前
Excalidraw 自建部署指南:白板协作工具完全私有化
服务器·网络·数据库
从零开始学习人工智能1 小时前
同文件同网络,curl 上传飞快,浏览器 HTTP/1.1 却慢到离谱?终于找到元凶!
网络·网络协议·http
程序员小白条1 小时前
别盲目卷算法!2026 程序员\&大学生,最稳的 AI 技术进阶路线全梳理
java·网络·人工智能·网络协议·http·面试
计算机安禾3 小时前
【计算机网络】第16篇:TCP流量控制——接收窗口调度的缓冲管理问题
网络·tcp/ip·计算机网络
中议视控3 小时前
网络中控系统通过推流软件实现可视化:RTSP,H265,WEB等推流
前端·网络
Cx330❀3 小时前
Qt 入门指南:从零搭建开发环境到第一个图形界面程序
xml·大数据·开发语言·网络·c++·人工智能·qt
南境十里·墨染春水3 小时前
linux 学习进展 网络编程 ——TCP 协议 TIME_WAIT 状态详解
linux·网络·学习
嵌入式×边缘AI:打怪升级日志4 小时前
[特殊字符] 摄像头模块(七):编写 V4L2 设备框架
网络·网络协议
小李子呢02114 小时前
前端八股网络浏览器---输入 URL 到页面呈现
前端·网络