TCP 和UDP通信流程

news2024/10/2 12:17:48

TCP 通信流程

        根据上图可以看到,TCP 服务器和客户端通信分为 TCP 服务端和客户端,需要先建立服务 端然后再建立客户端与之连接进行数据交互。
服务端编程步骤:
        1.使用 socket 创建流式套接字
        2.使用 bind 绑定将服务器绑定到 IP
        3.listen 监听客户端连接
        4.accept 阻塞等待客户端连接
客户端编程步骤:
        1.使用 socket 创建流式套接字
        2.connect 连接服务器
                客户端和服务器连接成功后就可以使用下面读写接口操作套接字进行通信
                读接口:read,recv,recvfrom
                写接口:write,send,sendto
连接断开时,直接使用 close 关闭套接字就行了,也可以使用 shutdown 接口关闭。

UDP 通信流程

        对于 UDP 通信,其实没有服务端和客户端之分的,反而有点类似于进程间通信一样,只需 要向对于的 IP 端去发送消息即可,上图中服务端的 bind 可有可无,它们之间进行通信的流程就是首先使用 socket 去创建一个数据包套接字用于 UDP 通信,然后就使用 sandto 进行发送消息,用 recvfrom 进行读取消息,不能使用 read 和 write 是因为 UDP 通信需要知道对方的 ip 地址的,而 read 和 write 是不具备该参数的。

TCP 通信程序简单实例

客户端程序实例:

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

void* read_ser(void *pad)
{
    pthread_detach(pthread_self()); //线程分离
    int soke_c=*(int*)pad;
    while (1)
    {
        char buf[1024] = {0};
        int ret = read(soke_c,buf,1024);
        if(ret <= 0)
        {
            perror("read error");
            pthread_exit(NULL);
        }
        printf("字节长度:%d,收到的信息:%s\n",ret,buf);
    }
}

int main(int argc, char const *argv[])
{
    if(argc != 3) //打开失败
    {
        printf("bro,you arg not Yes\n");
        return -1;
    }

    /*连接服务器*/
    int sock = socket(AF_INET, SOCK_STREAM, 0); //申请一个 IPV4 的流式套接字
    if(sock == -1) //申请套接字失败
    {
        perror("create socket error");
        return -1;
    }
    struct sockaddr_in Saddr; //保存服务器的地址信息的结构体
    memset(&Saddr,0,sizeof(struct sockaddr_in)); //清空结构体
    Saddr.sin_family = AF_INET; //协议族,AF_INET 表示使用 IPV4 的协议族
    Saddr.sin_port = htons(atoi(argv[2])); //端口号,但是要求的是网络字节序
    Saddr.sin_addr.s_addr = inet_addr(argv[1]); //32bit 的一个 IP地址
    int r = connect(sock,(struct sockaddr*)&Saddr,sizeof(Saddr)); //连接服务器
    if(r == -1) //连接失败
    {
        perror("connect error");
        return -1;
    }
    printf("连接成功,连接的服务器 ip 是%s,端口号是%s\n",argv[1],argv[2]);
    pthread_t tid;
    pthread_create(&tid, NULL,read_ser, (void*)&sock); //创建线程去接收服务器消息
    while(1)
    { 
        char buf[1024] = {0};
        memset(buf,0,sizeof(buf));
        scanf("%[^\n]",buf);
        printf("%ld\n",strlen(buf));
        int ret = write(sock,buf,strlen(buf));
        if(ret <= 0)
        {
            perror("sendto error");
            return -1;
        }
        printf("写了多少个字节:%d\n",ret);
    }
    close(sock); //关闭套接字
    return 0;
}

服务端程序实例:

#include<stdio.h>
#include<stdlib.h>
#include <signal.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include<netinet/in.h> //为了使用 IPV4 地址结构体
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>

//线程函数,处理和一个客户端的通信
void *my_func(void *arg)
{
    //线程分离
    pthread_detach(pthread_self());
    int *cp = (int *)arg;
    int ret;
    while(1)
    {
        ret = sendto(*cp,"nishiliangzaima?",20,0,NULL,0); //发送消息
        if(ret <= 0)
        {
            perror("sendto error");
            free(cp);
            pthread_exit(NULL);
        }
        char buf[1024] = {0};
        ret = read(*cp,buf,1024); //读取消息
        if(ret <= 0)
        {
            perror("recv error");
            free(cp);
            pthread_exit(NULL);
        }
        printf("recv size:%d,recv data:%s\n",ret,buf);
    }
}

//./main ip port
int main(int argc,char *argv[])
{
    if(argc != 3)
    {
        printf("please input ip + port!\n");
        return 0;
    }
    //1.创建一个套接字
    int sockfd = socket(AF_INET, SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("create socket failed");
        exit(-1);
    }
    //2.绑定一个通信 IP 地址(作为服务器本身的 IP)
    struct sockaddr_in saddr; //保存服务器的地址(IP+port)
    memset(&saddr,0,sizeof(struct sockaddr_in)); //清空结构体
    saddr.sin_family = AF_INET;
    inet_aton(argv[1], &saddr.sin_addr);
    saddr.sin_port = htons(atoi(argv[2]));
    int ret = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
    if(ret == -1)
    {
        perror("bind error");
        exit(-1);
    }
    printf("bind success\n");
    //3.开启对一个套接字的监听
    listen(sockfd,250);
    //4.等待客户端的连接
    while(1)
    {
        struct sockaddr_in caddr; //保存客户端的地址(IP+port)
        socklen_t len = sizeof(caddr);
        int *confp = (int *)malloc(sizeof(int));
        *confp = accept(sockfd,(struct sockaddr *)&caddr,&len);
        if(*confp > 0) //客户端连接成功,返回一个连接套接字专门用来和客户端通信
        {
            //一个客户端连接成功.开一个进程/线程去处理这个连接
            printf("client IP:%s,clientPort:%d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
            pthread_t tid;
            pthread_create(&tid,NULL,my_func,(void *)confp); //创建线程去处理和客户端的会话
        }
    }
    //关闭套接字
    shutdown(sockfd,SHUT_RDWR);
    close(sockfd);
    return 0;
}

UDP 通信程序简单实例

A 端:客户端

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include<netinet/in.h> //为了使用 IPV4 地址结构体
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

//./main ip port
int main(int argc,char *argv[])
{
    if(argc != 3) //判断输入是否正确
    {
        printf("please input ip + port!\n");
        return 0;
    }
    //1.创建一个 UDP 套接字
    int sockfd = socket(AF_INET,SOCK_DGRAM,0); //创建一个 IPV4 的数据报套接字
    if(-1 == sockfd)
    {
        perror("create socket failed");
        exit(-1);
    }
    //直接发送消息(定义一个接收消息的地址)
    struct sockaddr_in addr; //保存接收消息的地址(IP+port)
    memset(&addr,0,sizeof(struct sockaddr_in)); //清空结构体
    addr.sin_family = AF_INET;
    inet_aton(argv[1], &addr.sin_addr);
    addr.sin_port = htons(atoi(argv[2]));
    while(1)
    {
        char buf[1024] = {0};
        fgets(buf,1024,stdin);
        int ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&addr,sizeof(addr));//发送数据
        if(ret <= 0)
        {
            perror("sendto error");
        }
        printf("sendto size:%d\n",ret);
        //读取服务器的回复消息
        memset(buf,0,1024);
        struct sockaddr_in src_addr; //保存消息发送方的地址(IP+port)
        memset(&src_addr,0,sizeof(struct sockaddr_in)); //清空结构体
        socklen_t src_len = sizeof(src_addr); //保存可用大小
        ret = recvfrom(sockfd,buf,1024, 0,(struct sockaddr*)&src_addr,&src_len); //接收消息
        if(ret <= 0)
        {
            perror("recvfrom error");
        }
        printf("sendIP:%s,sendPort:%d\n",inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port));
        printf("recv size:%d,recv data:%s\n",ret,buf);
    }
    //关闭套接字
    shutdown(sockfd,SHUT_RDWR);
    close(sockfd);
    return 0;
}
B 端:服务端,当然在 UDP 通信中其实没有服务端客户端之言,不过倒是可以对一端进行服务
器般的操作。
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include<netinet/in.h> //为了使用 IPV4 地址结构体
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

//./main ip port
int main(int argc,char *argv[])
{
    if(argc != 3)
    {
        printf("please input ip + port!\n");
        return 0;
    }
    //1.创建一个 UDP 套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM,0); //创建一个 IPV4 的数据报套接字
    if(-1 == sockfd)
    {
        perror("create socket failed");
        exit(-1);
    }
    //2.绑定(可不绑定)
    struct sockaddr_in addr; //本地服务器的地址(IP+port)
    memset(&addr,0,sizeof(struct sockaddr_in)); //清空结构体
    addr.sin_family = AF_INET;
    inet_aton(argv[1], &addr.sin_addr);
    //addr.sin_addr.s_addr = INADDR_ANY; //让内核自动选择一个网卡
    addr.sin_port = htons(atoi(argv[2]));
    int ret = bind(sockfd,(struct sockaddr *)&addr,sizeof(addr)); //绑定一个 IP 和端口号,可不绑定
    if(ret == -1)
    {
        perror("bind error");
        exit(-1);
    }
    printf("bind success\n");
    while(1)
    {
        char buf[1024] = {0};
        //读取别人发送的消息
        struct sockaddr_in src_addr; //保存消息发送方的地址(IP+port)
        memset(&src_addr,0,sizeof(struct sockaddr_in)); //清空结构体
        socklen_t src_len = sizeof(src_addr); //保存可用大小
        ret = recvfrom(sockfd,buf,1024, 0,(struct sockaddr*)&src_addr,&src_len); //接收消息
        if(ret <= 0)
        {
            perror("recvfrom error");
        }
        printf("sendIP:%s,sendPort:%d\n",inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port));
        printf("recv size:%d,recv data:%s\n",ret,buf);
        ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&src_addr,sizeof(src_addr)); //发送消息
        if(ret <= 0)
        {
            perror("sendto error");
        }
    }
    //关闭套接字
    shutdown(sockfd,SHUT_RDWR);
    close(sockfd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1072168.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

测试小白必掌握软件测试十大原则

软件测试是确保软件质量的重要手段之一&#xff0c;它可以检测软件中的各种缺陷和问题&#xff0c;从而提高软件的可靠性、可用性和安全性。软件测试也是一项极富创造性、极具挑战性的工作。为了尽可能发现软件中的错误&#xff0c;提高软件产品的质量&#xff0c;在软件测试的…

不用休眠的 Kotlin 并发:深入对比 delay() 和 sleep()

本文翻译自&#xff1a; https://blog.shreyaspatil.dev/sleepless-concurrency-delay-vs-threadsleep 毫无疑问&#xff0c;Kotlin 语言中的协程 Coroutine 极大地帮助了开发者更加容易地处理异步编程。该特性中封装的诸多高效 API&#xff0c;可以确保开发者花费更小的精力去…

2023年中国隆鼻行业发展历程及趋势分析:隆鼻手术市场将实现进一步增长[图]

隆鼻术就是以各种植入材料置入为主要方法&#xff0c;隆起或抬高鼻部形态为主要目的的鼻整形术式。隆鼻术可能是开展最多的整形美容手术之一。隆鼻术也是一种很成熟的美容手术&#xff0c;操作较为简单、安全、风险较小&#xff0c;也易于接受。 隆鼻行业分类 资料来源&#x…

【2023研电赛】安谋科技企业命题特别奖:面向独居老人的智能居家监护系统

本文为2023年第十八届中国研究生电子设计竞赛安谋科技企业命题特别奖分享&#xff0c;参加极术社区的【有奖活动】分享2023研电赛作品扩大影响力&#xff0c;更有丰富电子礼品等你来领&#xff01;&#xff0c;分享2023研电赛作品扩大影响力&#xff0c;更有丰富电子礼品等你来…

滚雪球学Java(43):探究 Java 中的 Class 类:透视类的本质和实现原理

&#x1f3c6;本文收录于「滚雪球学Java」专栏&#xff0c;专业攻坚指数级提升&#xff0c;助你一臂之力&#xff0c;带你早日登顶&#x1f680;&#xff0c;欢迎大家关注&&收藏&#xff01;持续更新中&#xff0c;up&#xff01;up&#xff01;up&#xff01;&#xf…

科普丨语音芯片选型应遵守的原则

在选择语音芯片时&#xff0c;设计者应该首先详细了解设计要求&#xff0c;并从要求中整理出电路功能模块和性能指标要求。根据功能和性能要求&#xff0c;制定总体设计方案。一般来说&#xff0c;选择语音芯片有以下要求&#xff1a; 1、 性价比&#xff1a;选择物美价廉的语…

16.(开发工具篇mysql)mysql不同库同步数据的异常记录

1:mysql导入时出现“ERROR at line : Unknown command ‘\‘‘.“的解决办法 default-character-set=utf82:ERROR 2006 (HY000) at line 71: MySQL server has gone away (1) 连接超时 查看各项连接时间: show global variables like %timeout;这些值是相对是MySQL的默认…

Redis AOF重写原原理

重写aof之前 appendonly.aof.1.base.aof appendonly.aof.1.incr.aof appendonly.aof.manifest 重写aof 一次 appendonly.aof.2.base.aof 大小变化 appendonly.aof.2.incr.aof 大小o appendonly.aof.manifest 大小不变 AOF文件重写并不是对原文件进行重新整理&#xff0c;而是直…

web:[护网杯 2018]easy_tornado

题目 点进页面显示如下 点进去查看 有个render&#xff0c;结合题目名&#xff0c;可能是ssti 同时注意到url&#xff0c;无论点进哪个文件&#xff0c;url的格式都为file?filename/xxx&filehashxxx 所以结合hints.txt中的提示&#xff0c;filehash就是md5加密得到的&…

CasA:用于点云 3D 目标检测的级联注意力网络

论文摘要 LiDAR 收集的数据通常表现出稀疏和不规则的分布。 3D 空间中的 LiDAR 扫描并不均匀。近处和远处的物体之间存在巨大的分布差距。 CasA(Cascade Attention) 由 RPN&#xff08;Region proposal Network&#xff09;和 CRN&#xff08;cascade refinement Network&…

目标追踪算法DeepSORT简介

背景&#xff1a;目标检测 vs 目标跟踪 在开始介绍 DeepSORT 的原理之前呢&#xff0c;我们先来了解下目标检测&#xff0c;和目标跟踪之间的区别&#xff1a; 目标检测&#xff1a;在目标检测任务中&#xff0c;我们需要利用 AI 模型识别出单张画面中&#xff0c;物体的位置…

【稳定性】稳定性建设之弹性设计 | 京东物流技术团队

背景 随着业务的快速变化和技术的不断发展&#xff0c;系统面临着诸多挑战&#xff0c;例如流量峰值、依赖服务故障、硬件故障、网络中断、软件缺陷等&#xff0c;这些因素都可能影响到系统的正常运行。在这种背景下&#xff0c;弹性设计&#xff08;Resilience Design&#x…

开启深度学习之门—《深度学习》

开启深度学习之门—《深度学习》 《深度学习》由Ian Goodfellow和Yoshua Bengio合著,以其前沿的内容和深入浅出的风格,成为了当今最受欢迎的人工智能教材之一。首先,让我们来了解一下这两位作者。Ian Goodfellow是一位备受瞩目的计算机科学家,他在深度学习和生成对抗网络的…

第二证券:华为全液冷超充上线,高压快充概念爆发,双杰电气等涨停

受华为全液冷超充上线消息提振&#xff0c;高压快充概念9日盘中强势拉升&#xff0c;到发稿&#xff0c;双杰电气、永贵电器“20cm”涨停&#xff0c;英可瑞、易事特涨超13%&#xff0c;伊戈尔、协鑫能科、宝馨科技、日丰股份等涨停&#xff0c;万祥科技、星云股份涨近8%。 消…

外汇天眼:三大方法提高容错率——成功投资者的秘密策略!

容错率是什么&#xff1f; 虽然A股市场投资体验不佳&#xff0c;但相较于中概股市场的波动&#xff0c;A股投资者仍有幸福感。以中概股的代表&#xff0c;金龙指数ETF为例&#xff0c;仅一年多时间内从85.90元下跌至20.47元&#xff0c;跌幅高达76%。 然而&#xff0c;有一位…

【PPT】ppt里面使用svg图标

要想编辑好的PPT&#xff0c;少不了小图标的美化&#xff0c;图标可以使PPT变得更有趣&#xff0c;更易懂&#xff0c;更美观。 对于png&#xff0c;主要处理它的颜色&#xff0c;可使用【重新着色】功能。 对于jpg&#xff0c;主要处理它的背景&#xff0c;删除背景后同png处…

vue-6

一、声明式导航-导航链接 1.需求 实现导航高亮效果 如果使用a标签进行跳转的话&#xff0c;需要给当前跳转的导航加样式&#xff0c;同时要移除上一个a标签的样式&#xff0c;太麻烦&#xff01;&#xff01;&#xff01; 2.解决方案 vue-router 提供了一个全局组件 router…

进程同步互斥之吸烟者问题,读者写者问题,哲学家进餐问题

1.吸烟者问题 1.问题描述 假设一个系统有三个抽烟者进程和一个供应者进程。 每个抽烟者不停地卷烟并抽掉它&#xff0c;但是要卷起并抽掉一支烟&#xff0c;抽烟者需要有三种材料:烟草、纸和胶水。 三个抽烟者中&#xff0c;第一个拥有烟草、第二个拥有纸、第三个拥有胶水。 …

【MyBatis】MyBatis 详解

MyBatis 详解 一. MyBatis 是什么二. MyBatis 在整个框架中的定位三. MyBatis 的操作1. 先创建好数据库和表2. 添加MyBatis框架⽀持3. 修改配置文件4. 添加业务代码5. 增、删、改操作① 增加⽤户② 修改用户操作③ 删除操作 6. 查询操作① 单表查询② 多表查询 一. MyBatis 是什…

Ubuntu16.04apt更新失败

先设置网络设置 换成nat、桥接&#xff0c;如果发现都不行&#xff0c;那么就继续下面操作 1.如果出现一开始就e&#xff0c;检查源&#xff0c;先换源 2.换完源成功之后&#xff0c;ping网络&#xff0c;如果ping不通就是网络问题 如果ping baidu.com ping不通但是ping 112…