网络: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;
}
相关推荐
晚风吹长发11 小时前
Docker基础——Docker Network(网络详解)
linux·运维·网络·ubuntu·docker·容器
hz5678911 小时前
音视频SDK核心能力分析:低延迟传输与高并发接入方案
网络·安全·音视频·实时音视频·信息与通信
q5673152311 小时前
企业级 HTTP 代理采购选型:技术评估清单 15 项
开发语言·网络·爬虫·网络协议·http·隧道ip·代理ip
白嫖一茶11 小时前
HTTP 状态码详解:五大类与常见状态码解析
网络·网络协议·http
ai_xiaogui13 小时前
PanelAI没有域名也能装?IP安装+自签HTTPS+安全加固全攻略(私有化部署必备)
tcp/ip·安全·https·私有化部署·自签证书·panelai·自带https自动续证
oradh14 小时前
Oracle 11g rac IP地址修改(public ip、vip、scan ip、priviate ip)
数据库·tcp/ip·oracle·rac ip地址修改
treesforest14 小时前
如何解决IP定位精度不足导致的投放偏差
网络·网络协议·tcp/ip·ip属地·查ip归属地
茯苓gao15 小时前
嵌入式开发笔记:CAN与CAN FD完全指南——从帧格式差异到MCU选型实战
网络·笔记·stm32·嵌入式硬件·学习·汽车
奥莱维16 小时前
酒店客控系统与消防系统联动设计
网络
2401_8685347816 小时前
《论单元测试及其应用》
网络·网络协议