当前位置: 首页 > news >正文

TCP 和UDP通信流程

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.lryc.cn/news/186170.html

相关文章:

  • Swift SwiftUI CoreData 过滤数据 1
  • 【uniapp】subnvue组件数据更新视图未更新问题
  • Unity编辑器拓展-Odin
  • 小红书婴童产业探索,解析消费者需求!
  • 离线安装mysql客户端
  • Docker 数据管理
  • 数据统计--图形报表--ApacheEcharts技术 --苍穹外卖day10
  • 【kubernetes的三种网络】
  • Java中树形菜单的实现方式(超全详解!)
  • 基于Uniswap V3的去中心化前端现货交易平台Oku正式登陆Moonbeam
  • leetcode 每日一题复盘(10.9~10.15)
  • 【云计算网络安全】DDoS 缓解解析:DDoS 攻击缓解策略、选择最佳提供商和关键考虑因素
  • 如何巧用AI智能技术,让文物不再“无人问津”?
  • 一天一八股——SSL/TLS协议
  • SpringCloud学习笔记-Eureka服务的搭建
  • css如何实现页面布局与五种实现方式
  • cv2.split函数与cv2.merge函数
  • Vue--1.7watch侦听器(监视器)
  • 序列:全序关系
  • 100M服务器能同时容纳多少人访问?
  • Javascript 笔记:函数调用与函数上下文
  • 【WebService】C#搭建的标准WebService接口,在使ESB模版作为参数无法获取参数数据
  • Sqlserver关于tempdb临时数据库文件个数的最佳实践
  • 【Java】微服务——微服务介绍和Eureka注册中心
  • C++ virtual 虚函数 虚基类
  • redis分布式秒杀锁
  • 【Redis】String内部编码方式
  • 川西旅游网系统-前后端分离(前台vue 后台element UI,后端servlet)
  • Paddle使用pyinstaller打包出错的解决方法
  • 【Java acm】特殊输入