网络: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;
}
相关推荐
汤愈韬2 小时前
ip-prefix(IP前缀列表)
linux·服务器·网络协议·tcp/ip
dldw77710 小时前
IE无法正常登录windows2000server的FTP服务器
运维·服务器·网络
运维有小邓@10 小时前
什么是重放攻击?如何避免成为受害者?
运维·网络·安全
光路科技11 小时前
工业数字化三大核心概念拆解:IIoT、工业互联网与工业4.0
网络
汤愈韬11 小时前
下一代防火墙通用原理
运维·服务器·网络·security
有代理ip13 小时前
网络隐私防护指南:代理服务与换 IP 工具的科学结合
网络·tcp/ip·web安全
不是书本的小明14 小时前
阿里云专有云网络架构
网络·阿里云·架构
mounter62514 小时前
【内核前沿】从 veth 到 netkit:深度解析 TCP devmem 穿透容器屏障的“队列租赁”黑科技
网络·ebpf·linux kernel·devmem tcp·netkit·队列租赁
爱学习的小囧15 小时前
vSphere Supervisor 服务配置指南:自签名容器注册表使用教程
服务器·网络·esxi·虚拟化·vcf