《TCP与UDP通信原理与实践》

tcp与udp

  • TCP:可靠的,像“顺丰快递”,包裹一定送到,按顺序,签收确认。
  • UDP:不可靠的,像“扔报纸”,快速发,不管你收没收,不管顺不顺序。

TCP(Transmission Control Protocol)传输控制协议

特点:

特性描述
面向连接三次握手建立连接,断开也要四次挥手
可靠传输有确认、有重传、有序号,确保每个数据包都送达
有序传输接收的数据顺序和发送的保持一致
流量控制控制发送速度,防止接收方处理不过来
拥塞控制根据网络状况调整发送速率,防止网络拥堵

应用场景:

  • 网页访问(HTTP、HTTPS)
  • 文件传输(FTP)
  • 邮件传输(SMTP、POP3)

UDP(User Datagram Protocol)用户数据报协议

特点:

特性描述
无连接不建立连接,直接发,像发短信
不可靠传输不确认、不重传,可能丢包
更快更轻量没有 TCP 的各种机制,效率高,延迟低
不保证顺序数据到达顺序可能和发送顺序不同

应用场景:

  • 视频直播、语音通话(比如微信语音、腾讯会议)
  • DNS 查询(要的是快)
  • 游戏实时通信(延迟比丢包更重要)

关键区别对比

项目TCPUDP
是否连接有连接(三次握手)无连接
是否可靠可靠,保证顺序和送达不可靠,不保证顺序
是否慢一点是(因为有确认/重传)否(几乎实时)
应用网页/文件/邮箱视频/语音/游戏

一个类比帮助你理解:

TCP 就像打电话(“喂?能听见吗?”——要确认、能讲话、顺序讲)
UDP 就像发广播(“大家听好了,我说一遍,不管听没听见”)


接下来我用代码简单实现一下tcp的通讯效果。

tcp服务端代码

#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 <pthread.h>
#include <unistd.h>

#define handle_error(cmd, result) \
    if (result < 0)               \
    {                             \
        perror(cmd);              \
        return -1;                \
    }

void *read_from_client(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");
        }
        fputs(read_buf, stdout);
    }
    printf("客户端请求关闭\n");
    free(read_buf);
    return NULL;
}

void *write_from_client(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,1023,0);
        if(count<0)
        {
            perror("send");
        }
    }
    printf("接收到控制台的关闭请求不再写入 关闭连接\n");
    //可以具体关闭某一段
    shutdown(client_fd,SHUT_WR);
    free(write_buf);
    return NULL;
    

}

int main(int argc, char const *argv[])
{
    int sockfd,temp_result,clientfd;
    pthread_t pid_read,pid_write;
    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);
    //等价inet_pton(AF_INET,"0.0.0.0",server_addr.sin_addr.s_addr);
    //填写端口号
    server_addr.sin_port=htons(6666);

    //网络编程流程
    //1.socket
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    handle_error("socket",sockfd);
    //2.绑定地址
    temp_result=bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));;
    handle_error("bind",temp_result);

    //3.进入监听状态
    temp_result=listen(sockfd,128);
    handle_error("listen",temp_result);

    //4.获取客户端的连接
    socklen_t clientaddr_len=sizeof(client_addr);
    //返回的文件描述符才是能够和客户端收发消息的文件描述符
    //如果调用accept之后没有客户端连接,这里会挂起等待
    clientfd=accept(sockfd,(struct sockaddr *)&client_addr,&clientaddr_len);
    handle_error("accept",clientfd);
    
    printf("与客户端%s %d建立连接 文件描述符是%d",inet_ntoa(client_addr.sin_addr),
    ntohs(client_addr.sin_port),clientfd);

    //创建子线程用于收消息
    pthread_create(&pid_read,NULL,read_from_client,(void*)&clientfd);
    //创建子线程用于发消息
    pthread_create(&pid_write,NULL,write_from_client,(void*)&clientfd);

    //阻塞主线程
    pthread_join(pid_read,NULL);
    pthread_join(pid_write,NULL);
    printf("释放内存\n");
    close(clientfd);
    close(sockfd);

    return 0;
}

tcp客户端代码

#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 <pthread.h>
#include <unistd.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))
    {
        fputs(read_buf,stdout);
    }
    printf("服务端请求关闭\n");
    free(read_buf);
    return NULL;
}

void *write_from_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,1023,stdin)!=NULL)

    {
        //发送数据
        count=send(client_fd,write_buf,1023,0);
        if(count<0)
        {
            perror("send");
        }
    }
    printf("接收到控制台的关闭请求不再写入 关闭连接\n");
    //可以具体关闭某一段
    shutdown(client_fd,SHUT_WR);
    free(write_buf);
    return NULL;
    

}

int main(int argc, char const *argv[])
{
    int sockfd,temp_result;
    pthread_t pid_read,pid_write;
    struct sockaddr_in server_addr,client_addr;
    //清空
    memset(&server_addr,0,sizeof(server_addr));
    memset(&client_addr,0,sizeof(client_addr));
    //填写服务端地质
    client_addr.sin_family=AF_INET;
    //填写ip地址 0.0.0.0
    inet_pton(AF_INET,"192.168.6.101",&client_addr.sin_addr);
    //填写端口号
    client_addr.sin_port=htons(8888);

    server_addr.sin_family=AF_INET;
    inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr);
    //填写端口号
    server_addr.sin_port=htons(6666);

    //服务端网络编程流程
    //1.创建socket
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    handle_error("socket",sockfd);
    //2.绑定
    temp_result=bind(sockfd,(struct sockaddr *)&client_addr,sizeof(client_addr));
    handle_error("bind",sockfd);
    //3.主动连接服务端
    temp_result=connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
    handle_error("connect",sockfd);
    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_from_server,(void*)&sockfd);

    //阻塞主线程
    pthread_join(pid_read,NULL);
    pthread_join(pid_write,NULL);
    printf("释放内存\n");
    close(sockfd);

    return 0;
}

在实际应用中,我们的server是不可能只有一个client访问的,所以client后面是不需要绑定的,接下来我将展示tcpudp实现通讯的效果

tcp多线程通讯

server

#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 <pthread.h>
#include <unistd.h>

#define handle_error(cmd, result) \
    if (result < 0)               \
    {                             \
        perror(cmd);              \
        return -1;                \
    }

void *read_from_client_then_write(void *argv)
{
    int client_fd = *(int *)argv;

    ssize_t count = 0, send_count = 0;
    char *read_buf = NULL;
    char *write_buf = NULL;

    read_buf = malloc(sizeof(char) * 1024);
    // 判断内存是否分配成功
    if (!read_buf)
    {
        printf("服务端读缓存创建异常,断开连接\n");
        shutdown(client_fd, SHUT_WR);
        close(client_fd);
        perror("malloc sever read_buf");
        return NULL;
    }

    // 判断内存是否分配成功
    write_buf = malloc(sizeof(char) * 1024);
    if (!write_buf)
    {
        printf("服务端写缓存创建异常,断开连接\n");
        free(read_buf);
        shutdown(client_fd, SHUT_WR);
        close(client_fd);
        perror("malloc server write_buf");
        return NULL;
    }

    while ((count = recv(client_fd, read_buf, 1024, 0)))
    {
        if (count < 0)
        {
            perror("recv");
        }
        printf("reveive message from client_fd: %d: %s\n", client_fd, read_buf);

        strcpy(write_buf, "reveived~\n");
        send_count = send(client_fd, write_buf, 1024, 0);
        if (send_count < 0)
        {
            perror("send");
        }
    }

    printf("客户端client_fd: %d请求关闭连接......\n", client_fd);
    strcpy(write_buf, "receive your shutdown signal\n");

    send_count = send(client_fd, write_buf, 1024, 0);
    if (send_count < 0)
    {
        perror("send");
    }

    printf("释放client_fd: %d资源\n", client_fd);
    shutdown(client_fd, SHUT_WR);
    close(client_fd);
    free(read_buf);
    free(write_buf);

    return NULL;
}

int main(int argc, char const *argv[])
{
    int sockfd, temp_result;

    struct sockaddr_in server_addr, client_addr;

    memset(&server_addr, 0, sizeof(server_addr));
    memset(&client_addr, 0, sizeof(client_addr));

    // 声明IPV4通信协议
    server_addr.sin_family = AF_INET;
    // 我们需要绑定0.0.0.0地址,转换成网络字节序后完成设置
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    // 端口随便用一个,但是不要用特权端口
    server_addr.sin_port = htons(6666);

    // 创建server socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    handle_error("socket", sockfd);

    // 绑定地址
    temp_result = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    handle_error("bind", temp_result);

    // 进入监听模式
    temp_result = listen(sockfd, 128);
    handle_error("listen", temp_result);

    socklen_t cliaddr_len = sizeof(client_addr);

    // 接受client连接
    while (1)
    {
        int client_fd = accept(sockfd, (struct sockaddr *)&client_addr, &cliaddr_len);
        handle_error("accept", client_fd);

        printf("与客户端 from %s at PORT %d 文件描述符 %d 建立连接\n",
               inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_fd);

        pthread_t pid_read_write;

        // 启动一个子线程,用来读取客户端数据,并打印到 stdout
        // 要注意,此处的pid_read_write并不是线程ID,而是用于线程处理函数的标识符
        if (pthread_create(&pid_read_write, NULL, read_from_client_then_write, (void *)&client_fd))
        {
            perror("pthread_create");
        }

        // 将子线程处理为detached状态,使其终止时自动回收资源,同时不阻塞主线程
        pthread_detach(pid_read_write);
        printf("创建子线程并处理为detached状态\n");
    }

    printf("释放资源\n");
    close(sockfd);

    return 0;
}

client

#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 *argv)
{
    int sockfd = *(int *)argv;
    char *read_buf = NULL;
    ssize_t count = 0;

    read_buf = malloc(sizeof(char) * 1024);
    if (!read_buf)
    {
        perror("malloc client read_buf");
        return NULL;
    }

    while (count = recv(sockfd, read_buf, 1024, 0))
    {
        if (count < 0)
        {
            perror("recv");
        }
        fputs(read_buf, stdout);
    }

    printf("收到服务端的终止信号......\n");
    free(read_buf);

    return NULL;
}

void *write_to_server(void *argv)
{
    int sockfd = *(int *)argv;
    char *write_buf = NULL;
    ssize_t send_count;

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

    if (!write_buf)
    {
        printf("写缓存申请异常,断开连接\n");
        shutdown(sockfd, SHUT_WR);
        perror("malloc client write_buf");
        return NULL;
    }

    while (fgets(write_buf, 1024, stdin) != NULL)
    {
        send(sockfd, write_buf, 1024, 0);
        if (send_count < 0)
        {
            perror("send");
        }
    }

    printf("接收到命令行的终止信号,不再写入,关闭连接......\n");
    shutdown(sockfd, SHUT_WR);
    free(write_buf);

    return NULL;
}

int main(int argc, char const *argv[])
{
    int sockfd, temp_result;
    pthread_t pid_read, pid_write;

    struct sockaddr_in server_addr;

    memset(&server_addr, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    // 连接本机 127.0.0.1
    server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    // 连接端口 6666
    server_addr.sin_port = htons(6666);

    // 创建socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    handle_error("socket", sockfd);

    // 连接server
    temp_result = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    handle_error("connect", temp_result);

    // 启动一个子线程,用来读取服务端数据,并打印到 stdout
    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("关闭资源\n");
    close(sockfd);

    return 0;
}

tcp进程通讯

server

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>

#define handle_error(cmd, result) \
    if (result < 0)               \
    {                             \
        perror(cmd);              \
        return -1;                \
    }

void zombie_dealer(int sig) {
    pid_t pid;
    int status;
    // 一个SIGCHLD可能对应多个子进程的退出
    // 使用while循环回收所有退出的子进程,避免僵尸进程的出现
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status)) {
            printf("子进程: %d 以 %d 状态正常退出,已被回收\n", pid, WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("子进程: %d 被 %d 信号杀死,已被回收\n", pid, WTERMSIG(status));
        } else {
            printf("子进程: %d 因其它原因退出,已被回收\n", pid);
        }
    }
}

void *read_from_client_then_write(void *argv)
{
    int client_fd = *(int *)argv;

    ssize_t count = 0, send_count = 0;
    char *read_buf = NULL;
    char *write_buf = NULL;

    read_buf = malloc(sizeof(char) * 1024);
    // 判断内存是否分配成功
    if (!read_buf)
    {
        printf("服务端pid: %d: 读缓存创建异常,断开连接\n", getpid());
        shutdown(client_fd, SHUT_WR);
        close(client_fd);
        perror("malloc sever read_buf");
        return NULL;
    }

    // 判断内存是否分配成功
    write_buf = malloc(sizeof(char) * 1024);
    if (!write_buf)
    {
        printf("服务端pid: %d: 写缓存创建异常,断开连接\n", getpid());
        free(read_buf);
        shutdown(client_fd, SHUT_WR);
        close(client_fd);
        perror("malloc server write_buf");
        return NULL;
    }

    while ((count = recv(client_fd, read_buf, 1024, 0)))
    {
        if (count < 0)
        {
            perror("recv");
        }
        printf("服务端pid: %d: reveive message from client_fd: %d: %s\n", getpid(), client_fd, read_buf);

        sprintf(write_buf, "服务端pid: %d: reveived~\n", getpid());
        send_count = send(client_fd, write_buf, 1024, 0);
        if (send_count < 0)
        {
            perror("send");
        }
    }

    printf("服务端pid: %d: 客户端client_fd: %d请求关闭连接......\n", getpid(), client_fd);
    sprintf(write_buf, "服务端pid: %d: receive your shutdown signal\n", getpid());

    send_count = send(client_fd, write_buf, 1024, 0);
    if (send_count < 0)
    {
        perror("send");
    }

    printf("服务端pid: %d: 释放client_fd: %d资源\n", getpid(), client_fd);
    shutdown(client_fd, SHUT_WR);
    close(client_fd);
    free(read_buf);
    free(write_buf);

    return NULL;
}

int main(int argc, char const *argv[])
{
    int sockfd, temp_result;

    struct sockaddr_in server_addr, client_addr;

    memset(&server_addr, 0, sizeof(server_addr));
    memset(&client_addr, 0, sizeof(client_addr));

    // 声明IPV4通信协议
    server_addr.sin_family = AF_INET;
    // 我们需要绑定0.0.0.0地址,转换成网络字节序后完成设置
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    // 端口随便用一个,但是不要用特权端口
    server_addr.sin_port = htons(6666);

    // 创建server socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    handle_error("socket", sockfd);

    // 绑定地址
    temp_result = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    handle_error("bind", temp_result);

    // 进入监听模式
    temp_result = listen(sockfd, 128);
    handle_error("listen", temp_result);

    socklen_t cliaddr_len = sizeof(client_addr);

    // 注册信号处理函数,处理SIGCHLD信号,避免僵尸进程出现
    signal(SIGCHLD, zombie_dealer);

    // 接受client连接
    while (1)
    {
        int client_fd = accept(sockfd, (struct sockaddr *)&client_addr, &cliaddr_len);
        handle_error("accept", client_fd);

        pid_t pid = fork();

        if (pid > 0)
        {
            printf("this is father, pid is %d, continue accepting...\n", getpid());

            // 父进程不需要处理client_fd,释放文件描述符,使其引用计数减一,以便子进程释放client_fd后,其引用计数可以减为0,从而释放资源
            close(client_fd);
        }
        else if (pid == 0)
        {
            // 子进程不需要处理sockfd,释放文件描述符,使其引用计数减一
            close(sockfd);
            printf("与客户端 from %s at PORT %d 文件描述符 %d 建立连接\n",
                   inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_fd);
            printf("新的服务端pid为: %d\n", getpid());
            // 读取客户端数据,并打印到 stdout
            read_from_client_then_write((void *)&client_fd);

            // 释放资源并终止子进程
            close(client_fd);
            exit(EXIT_SUCCESS);
        }
    }

    printf("释放资源\n");
    close(sockfd);

    return 0;
}

client

这里的客户端程序与tcp多线程下client代码一致

udp通讯

server


#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>
#define handle_error(cmd, result) \
    if (result < 0)               \
    {                             \
        perror(cmd);              \
        return -1;                \
    }

int main(int argc, char const *argv[])
{
    //使用udp实现客户端和服务端的通讯
    //EOF作为关闭信号
    int sockfd, temp_result;
    char * buf=malloc(1024);
    struct sockaddr_in server_addr, client_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    memset(&client_addr, 0, sizeof(client_addr));
    // 声明IPV4通信协议
    server_addr.sin_family = AF_INET;
    // 我们需要绑定0.0.0.0地址,转换成网络字节序后完成设置
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    // 端口随便用一个,但是不要用特权端口
    server_addr.sin_port = htons(6666);
    
    //udp编程流程
    //1.socket创建
    sockfd=socket(AF_INET,SOCK_DGRAM,0);
    handle_error("socket",sockfd);
    //2.绑定
    temp_result=bind(sockfd,(struct sockaddr*)&server_addr, sizeof(server_addr));
    handle_error("bind",temp_result);
    //3.直接就可以收发数据了
    do
    {
        //接收数据存到缓冲
        memset(buf,0,1024);
        temp_result = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr*)&client_addr, &(socklen_t){sizeof(client_addr)});
        handle_error("recvfrom",temp_result);
        if(strncmp(buf,"EOF",3)!=0)
        {
            printf("接收到客户端%s %d信息:%s\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),buf);
            strcpy(buf,"ok\n");
        }else
        {
            printf("收到结束信息,准备关闭\n");
            
        }
        temp_result=sendto(sockfd,buf,4,0,(struct sockaddr*)&client_addr, sizeof(client_addr));
        handle_error("sento",temp_result);

    } while (strncmp(buf,"EOF",3));
    free(buf);
    close(sockfd);
    return 0;
}

client

#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<unistd.h>

#define handle_error(cmd, result) \
    if (result < 0)               \
    {                             \
        perror(cmd);              \
        return -1;                \
    }

int main(int argc, char const *argv[])
{
    //使用udp实现客户端和服务端的通讯
    //EOF作为关闭信号
    int sockfd, temp_result;
    char * buf=malloc(1024);
    struct sockaddr_in server_addr, client_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    memset(&client_addr, 0, sizeof(client_addr));
    // 声明IPV4通信协议
    server_addr.sin_family = AF_INET;
    // 我们需要绑定0.0.0.0地址,转换成网络字节序后完成设置
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    // 端口随便用一个,但是不要用特权端口
    server_addr.sin_port = htons(6666);
    
    //udp编程流程
    //1.socket创建
    sockfd=socket(AF_INET,SOCK_DGRAM,0);
    handle_error("socket",sockfd);
    //3.直接就可以收发数据了
    do
    {   
        printf("请输入你想要发送的数据\n");
        //从控制台读取数据并发送
        int buf_len=read(STDIN_FILENO,buf,1024);
        temp_result=sendto(sockfd,buf,buf_len,0,(struct sockaddr*)&server_addr,sizeof(server_addr));
        handle_error("send",temp_result);
        //清空缓存并打印
        memset(buf, 0,1024);
        temp_result=recvfrom(sockfd,buf,1024,0,NULL,NULL);
        handle_error("recvfrom",temp_result);
        if(strncmp(buf,"EOF",3))
        {
            
            printf("接受到服务端%s %d的信息:%s\n",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port),buf);
        }
        
    } while (strncmp(buf,"EOF",3));
    free(buf);
    close(sockfd);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值