视频操作演示:

利用TCP/UDP 协议制作一个飞秋聊天工具演示视频

int udp_broadcast(char const*argv[])
{//1.创建对象udp_socket = socket(AF_INET, SOCK_DGRAM, 0);if(udp_socket<0){perror("");return -1;}//开启广播功能 int on=1; //开启int ret =  setsockopt(udp_socket,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)); if(ret < 0){perror("广播开启失败:");return -1; }else {printf("广播开启成功\n");}  //设置广播地址 dest_addr.sin_family=AF_INET; //设置网络协议 dest_addr.sin_port=htons(udp_port); //所有处于192.168.64网段且,端口为 6666 的进程都可以收到数据 dest_addr.sin_addr.s_addr=inet_addr("192.168.1.255"); //设置广播地址 //绑定IP地址信息 struct sockaddr_in server_addr;server_addr.sin_family=AF_INET; //设置网络协议 server_addr.sin_port=htons(udp_port); //所有处于192.168.64网段且,端口为 6666 的进程都可以收到数据 server_addr.sin_addr.s_addr = INADDR_ANY;  ret=bind(udp_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)); if(ret  < 0){perror("");// return  -1;}  else{printf("绑定udp成功\n");}   bind_tcp_serv(8989); //绑定接收文件的tcp服务器bind_sharetcp_serv(9898); //绑定接收文件的tcp服务器9898//创建一个线程接收udp数据pthread_t tid;pthread_create(&tid, NULL,recv_task, NULL);  //创建一个线程接收tcp发送的文件pthread_t tid1;pthread_create(&tid1, NULL,recv_tcpfile, NULL);   //拼接回发通知协议 char *weather_str = getweather((char *)argv[3]);  //(char *)argv[3]if(weather_str == NULL){printf("http请求获取签名失败 可能网络问题 请重新尝试\n");//return -1;exit(0);}//printf("你的个性签名:%s\n", weather_str);sprintf(people,"%s %s %s 个性签名:%s %s %s\n","##reply",argv[1],argv[2],weather_str,share_path,all_share_file);//拼接登陆通知协议 char loin[1024]={0};  sprintf(loin,"%s %s %s %s %s %s\n","##loin",argv[1],argv[2],weather_str,share_path,all_share_file);//设计登陆通知协议   loin  姓名  IP //发送一个UDP 广播数据报sendto(udp_socket,loin,strlen(loin),0,(struct sockaddr *)&dest_addr,sizeof(dest_addr)); }

设计目标:利用TCP/UDP 协议制作一个飞秋聊天工具

功能描述:

1.实现上.下线通知。 2.实现上线获取在线好友,下线删除好友。 3.实现单独聊天,群聊 (组播) 4.实现文件传输 5.实现文件共享 6.通过http请求获取天气信息,显示到 个性签名中, 心情中

**设计方案**

设计一个好友结构体:
struct people
{//姓名 //IP信息 //通信描述符 //个性签名 //所在组播//共享的文件路径  //设计链表  单链,双链,内核链
}

利用tcp/udp/http协议多线程等实现网络的通信,设计网络通信协议和用单链表来实现不同主机之间信息的交互。

系统框架

界面设计

此次之间用的终端实现聊天室的功能,简单用文字来实现

      printf("======网络聊天系统====\n");printf("1.获取在线好友 2.指定好友聊天 3.群聊 4.发送文件 5.共享文件  6.退出系统\n");printf("======================\n\n");    

实现过程

主函数

//主函数
int main(int argc, char const*argv[])
{signal(2, catch_sigint);//捕捉ctrl+c信号if(argc != 4){printf("请输入姓名和IP  ./main 姓名 IP 城市\n");return -1; }  printf("请输入共享文件路径\n");  scanf("%s",share_path);serch_dir(share_path);printf("%s||%s\n",share_path,all_share_file);//0.创建单链表头结点 设置共享head = malloc(sizeof(struct node));udp_broadcast(argv);//开启广播while (1){int n;printf("======网络聊天系统====\n");printf("1.获取在线好友 2.指定好友聊天 3.群聊 4.发送文件 5.共享文件  6.退出系统\n");printf("======================\n\n");      scanf("%d", &n);if(n == 1){//遍历链表Traver_Nodes(head);}else if( n == 2){char buf_name[256] = {0};char buf_ip[124] = {0};    char buf_msg[1024] = {0};char all_msg[1024] = {0};//指定好友发送消息printf("请输入好友的IP\n");scanf("%s", buf_ip);//获取 好友 的 ip 和端口struct sockaddr_in dest_addr;dest_addr.sin_family=AF_INET; //设置网络协议 dest_addr.sin_port=htons(udp_port);  //atoi(argv[4])dest_addr.sin_addr.s_addr=inet_addr(buf_ip);  printf("进入聊天成功!按quit退出\n");while (1){printf("请输入发送的信息\n");  scanf("%s", buf_msg);  sprintf(all_msg,"##msg %s",buf_msg);  if(strcmp(buf_msg,"quit")== 0){break;}  sendto(udp_socket,all_msg,strlen(all_msg),0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));   }}else if( n == 3){//群聊 组播char group[124] = {0};printf("请输入群聊的组播号:\n");scanf("%s", group);//1.加入组播struct ip_mreq a;bzero(&a, sizeof(a));a.imr_interface.s_addr = INADDR_ANY; //所有网卡地址加入组播 a.imr_multiaddr.s_addr = inet_addr(group); // 指定多播地址 //开启组播功能 int ret = setsockopt(udp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &a, sizeof(a));    if(ret < 0){perror("");}else{printf("开启组播成功\n");}printf("进入群聊成功!按quit退出\n");while (1){//4.往组播地址中发送数据 struct sockaddr_in arry_addr;arry_addr.sin_family=AF_INET;arry_addr.sin_port=htons(udp_port);arry_addr.sin_addr.s_addr=inet_addr(group); //所有网卡地址 printf("请输入内容\n");char buf[512]={0};char msgbuf[1024]={0};scanf("%s",buf);sprintf(msgbuf,"##all %s %s", argv[1], buf);//拼接群里消息标志##allif(strncmp(buf,"quit",4) == 0){break;}sendto(udp_socket,msgbuf,strlen(msgbuf),0,(struct sockaddr *)&arry_addr,sizeof(arry_addr));}}else if( n == 4){//发送文件char file_name[124] = {0};char ip[124] = {0};printf("发送文件中。。|请输入文件名\n");scanf("%s",file_name);printf("请输入好友的ip\n");scanf("%s",ip);send_file(file_name,ip,8989); 发送文件 端口设置8989    }else if( n == 5){//文件共享  共享自己的文件路径  如果别人进入点进来下载 你再发送这个文件给他 他接收 即可//1.查看好友的共享文件char ip[125] = {0};char pathname[512] = {0};char msgbuf[1024] = {0};char file[256] = {0};Traver_sharepath_Nodes(head);printf("请输入好友的ip\n");scanf("%s",ip);struct node *p= Find_IP_Nodes(head,ip);//利用ip查找该节点printf("%s\n",p->share_file);//打印节点的共享文件信息printf("请输入你要下载文件好友的文件\n");scanf("%s",file);sprintf(pathname,"%s%s",p->pathname,file);//发送udp数据告诉好友 需要下载//获取 好友 的 ip 和端口struct sockaddr_in dest_addr;dest_addr.sin_family=AF_INET; //设置网络协议 dest_addr.sin_port=htons(udp_port);  //dest_addr.sin_addr.s_addr=inet_addr(ip);  sprintf(msgbuf,"##share %s", pathname);//拼接群里消息标志##allsendto(udp_socket,msgbuf,strlen(msgbuf),0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));recv_sharefile();//接收共享文件}else if( n == 6){//退出 //拼接退出通知协议 char quit[1024]={0};  sprintf(quit,"%s %s %s\n","##quit",argv[1],argv[2]);//设计退出通知协议   quit 姓名  IP //发送一个UDP 广播数据报int ret = sendto(udp_socket,quit,strlen(quit),0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));  if(ret < 0 ){perror("");} close(udp_socket);system("killall -9 main");//有时退出的时候进程会还在 得关了否则会出现udp绑定失败return -1;      }}return 0;
}

//广播消息

int udp_broadcast(char const*argv[])
{//1.创建对象udp_socket = socket(AF_INET, SOCK_DGRAM, 0);if(udp_socket<0){perror("");return -1;}//开启广播功能 int on=1; //开启int ret =  setsockopt(udp_socket,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)); if(ret < 0){perror("广播开启失败:");return -1; }else {printf("广播开启成功\n");}  //设置广播地址 dest_addr.sin_family=AF_INET; //设置网络协议 dest_addr.sin_port=htons(udp_port); //所有处于192.168.64网段且,端口为 6666 的进程都可以收到数据 dest_addr.sin_addr.s_addr=inet_addr("192.168.1.255"); //设置广播地址 //绑定IP地址信息 struct sockaddr_in server_addr;server_addr.sin_family=AF_INET; //设置网络协议 server_addr.sin_port=htons(udp_port); //所有处于192.168.64网段且,端口为 6666 的进程都可以收到数据 server_addr.sin_addr.s_addr = INADDR_ANY;  ret=bind(udp_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)); if(ret  < 0){perror("");// return  -1;}  else{printf("绑定udp成功\n");}   bind_tcp_serv(8989); //绑定接收文件的tcp服务器bind_sharetcp_serv(9898); //绑定接收文件的tcp服务器9898//创建一个线程接收udp数据pthread_t tid;pthread_create(&tid, NULL,recv_task, NULL);  //创建一个线程接收tcp发送的文件pthread_t tid1;pthread_create(&tid1, NULL,recv_tcpfile, NULL);   //拼接回发通知协议 char *weather_str = getweather((char *)argv[3]);  //(char *)argv[3]if(weather_str == NULL){printf("http请求获取签名失败 可能网络问题 请重新尝试\n");//return -1;exit(0);}//printf("你的个性签名:%s\n", weather_str);sprintf(people,"%s %s %s 个性签名:%s %s %s\n","##reply",argv[1],argv[2],weather_str,share_path,all_share_file);//拼接登陆通知协议 char loin[1024]={0};  sprintf(loin,"%s %s %s %s %s %s\n","##loin",argv[1],argv[2],weather_str,share_path,all_share_file);//设计登陆通知协议   loin  姓名  IP //发送一个UDP 广播数据报sendto(udp_socket,loin,strlen(loin),0,(struct sockaddr *)&dest_addr,sizeof(dest_addr)); }

//线程接收消息函数

void *recv_task(void *arg)
{char sign_buf[124] ={0};char ip_buf[50] ={0};char name_buf[50] ={0};   char path[125] ={0};   char share_file[4096] ={0};   struct sockaddr_in clien_addr;int len=sizeof(clien_addr);      //等待用户回发数据while (1){    char msg[1024]={0};int ret = recvfrom(udp_socket,msg,1024,0,(struct sockaddr*)&clien_addr,&len);char *ip = inet_ntoa(clien_addr.sin_addr);unsigned short port = ntohs(clien_addr.sin_port);//2.设置接收者的地址struct sockaddr_in dest_addr;dest_addr.sin_family = AF_INET; //设置网络协议dest_addr.sin_port = htons(port);dest_addr.sin_addr.s_addr = inet_addr(ip);          // printf("ret%d msg:%s\n",ret,msg);if(ret > 0){if(strncmp(msg,"##loin",6)==0) //登陆通知 {sscanf(msg,"##loin %s %s %s %s %s",name_buf,ip_buf,sign_buf,path,share_file);printf("[%s]:%s上线了", name_buf, ip_buf);  printf("个性签名:%s\n",sign_buf);//判断是否存在链表中 不存在则加入链表if(FindNodes(head, name_buf) == NULL) {//加入链表中Insert_Node_tail(head,udp_socket,name_buf,ip_buf,sign_buf,share_path,share_file);}//回发自己的信息sendto(udp_socket,people,strlen(people),0,(struct sockaddr*)&dest_addr,len);continue;}if(strncmp(msg,"##reply",7)==0) //回发自己信息 让别人的好友列表有你在!{//##reply 小明 192.168.1.211 个性签名:city:揭阳Time:2022-09-0420:55:08weather:多云temp:32.00 ./ ||1.pngsscanf(msg,"##reply %s %s 个性签名:%s %s %s",name_buf,ip_buf,sign_buf,path,share_file);//判断是否存在链表中 不存在则加入链表if(FindNodes(head, name_buf) == NULL) {//加入链表中              Insert_Node_tail(head,udp_socket,name_buf,ip_buf,sign_buf,share_path,share_file);}continue;}if(strncmp(msg,"##quit",6)==0) //退出通知{sscanf(msg,"##quit %s %s",name_buf,ip_buf);printf(" [%s] %s:下线了\n",ip_buf, name_buf);//判断是否存在链表中 存在则删除if(FindNodes(head, name_buf) != NULL) {Remove_Node(head, name_buf);}  continue;          }if(strncmp(msg,"##share",7)==0) //接收共享文件请求 发送文件给好友{   sscanf(msg,"##share %s",share_path);printf("收到[%s]共享文件下载请求\n",ip);//tcp发送共享文件send_file(share_path,ip,9898);continue;}if(strncmp(msg,"##msg",5) == 0) //接收好友私聊{char strmsg[1024] = {0};sscanf(msg,"##msg %s",strmsg);printf("[%s] %d: %s\n",ip, port, strmsg );continue;}if(strncmp(msg,"##all",5) == 0) //接收群聊消息{  //##all[小明] 192.168.1.211: 66 char strname[128] = {0};char msg1[1024] = {0};sscanf(msg,"##all %s %s",strname,msg1);printf("群聊消息: %s[%s] : %s\n",strname,ip, msg1);}            }}
}

接收文件线程

//接收文件线程
void *recv_tcpfile(void *arg)
{printf("服务器启动了。。\n");while (1){int ret =recv_file();//接收文件 端口设置6666if(ret == -1){break;}}}

捕捉ctrl+c信号  

void catch_sigint(int arg)
{//退出 printf("触发键盘信号函数\n");//拼接退出通知协议 char quit[1024]={0};  char name_buf[512] = {0};char ip_buf[128] = {0};sscanf(people,"##reply %s %s 个性签名:",name_buf,ip_buf);sprintf(quit,"%s %s %s\n","##quit",name_buf,ip_buf);//设计退出通知协议   quit 姓名  IP //发送一个UDP 广播数据报int ret = sendto(udp_socket,quit,strlen(quit),0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));  if(ret < 0 ){perror("");} close(udp_socket);system("killall -9 main");//有时退出的时候进程会还在 得关了否则会出现udp绑定失败}

 tcp实现文件接收发送协议:

好友先绑定tcp服务器的端口,自己连接服务器 发送文件信息头(名字+大小)给好友,好友接收到头信息回发 可以发送了 创建文件并使用read接收文件 write写入文件,然后自己发送文件的内容write/send 好友接收并保存。 

//文件发送函数
int send_file(char *pathname, char *ip ,int port)
{//发送文件名与大小给服务器  file 文件名 文件大小int fd = open(pathname,O_RDWR);if(fd < 0){perror("");return -1;}//1.创建客户端通信socket int   tcp_socket1 = socket(AF_INET, SOCK_STREAM, 0);if(tcp_socket1 < 0 ){perror("");}//2.设置服务器信息struct sockaddr_in   addr; addr.sin_family = AF_INET; //ipv4 addr.sin_port   = htons(port);//端口为 8686addr.sin_addr.s_addr = inet_addr(ip); //本地网卡地址//链接服务器int ret=connect(tcp_socket1,(struct sockaddr *)&addr,sizeof(addr));if(ret < 0){perror("链接失败\n");return -1; }else{printf("连接好友成功 准备发送文件\n");}//获取文件大小struct stat  file_size; stat(pathname,&file_size); char file_msg[1024]={0};//拼接协议  sprintf(file_msg,"file %s %ld",pathname,file_size.st_size); //发送给服务器 int a = write(tcp_socket1,file_msg,strlen(file_msg));//等待服务器应答 char  req[1024]={0}; read(tcp_socket1,req,1024); if(strcmp(req,"get_file_msg") == 0)  //应答成功 {//发送文件内容 while (1){//读取源文件数据 char  data[4096]={0}; int size = read(fd,data,4096);if(size <= 0){printf("发送完毕\n");break;}//发送到网络中write(tcp_socket1,data,size);}}//等待服务器接收完毕 bzero(req,1024); read(tcp_socket1,req,1024); // write(new_socet,"down_ok",strlen("down_ok"));if(strcmp(req,"down_ok") == 0){printf("关闭所有链接\n");close(tcp_socket1);close(fd); }
}
//接收文件
int recv_file()
{//4.接收客户端的连接请求 printf("等待客户端发送文件\n");int  new_socet = accept(tcp_socket,NULL,NULL);if(new_socet > 0)  //连接成功 {printf("开始接收………\n");//接收文件名+文件大小 char file_msg[1024]; //file 文件名 文件大小 read(new_socet,file_msg,1024);//获取文件名和文件大小  char file_name[1024];  int file_size; if(strstr(file_msg,"file")){sscanf(file_msg,"file %s %d",file_name,&file_size); }else{printf("解析文件失败\n");close(new_socet); //continue;}printf("对方发送的文件名 %s,文件大小 %d\n",file_name,file_size);//告诉发送端,已经得到了文件的信息  write(new_socet,"get_file_msg",strlen("get_file_msg"));//创建文件 int fd = open(file_name,O_RDWR|O_CREAT|O_TRUNC,0777);//下载大小  int down_size=0; //不断接收数据 while (1){//读取网络数据char data[4096]={0};int size = read(new_socet,data,4096); down_size+=size; //写入本地文件 write(fd,data,size);//判断是否下载完毕  if(down_size >= file_size)  {printf("下载完毕\n");//告诉发送端已经下载完毕,可以断开链接 write(new_socet,"down_ok",strlen("down_ok"));close(fd);close(new_socet);break;}else{printf("下载进度 %d %%\n",down_size*100/file_size);}}}}

链表操作:

struct node
{char name[50];char ip[50];int socket; //描述符char signature[1024];//个性签名char pathname[512];//共享文件路径char share_file[2048];//共享文件夹下的所有文件struct node *next;
};

项目难点

第一个是udp/tcp协议的拼接使用,通过判断标志位来分别数据的不同和数据操作传输。

第二个是由于自己校园网 使用ucp比较繁琐 最终使用路由器解决 (开发板连接路由器,电脑连接路由器的网)但开发板有个缺点不支持udp组播。

得设置绑定本地所有网卡 开发板或者虚拟机才能正常使用,广播发送接收数据。。。。 一开始的绑定自己的ip 

第三个是关闭的时候有时进程还在运行 得用killall -9 把进程关闭

心得体会

此次网络编程项目运用的知识点比较广泛,基本覆盖了整个所学的知识,认识到udp/tcp/http等协议的实际编程运用,实现跨主机的数据交互。进一步提高自己的代码知识,项目代码编写更加规范。

利用TCP/UDP 协议制作一个飞秋聊天工具相关推荐

  1. 利用TCP传输协议实现基于Socket的聊天程序(高级版_多线程)

    大家好,在上篇<利用TCP和UDP协议,实现基于Socket的小聊天程序(初级版)>博客中,所写程序只是实现简单的连接通信,基于控制台实现,运用了TCP和UDP两种传输协议.今天我和大家分 ...

  2. 网络编程—网络基础概览、socket,TCP/UDP协议

    网络基础概览 socket概览 socket模块-TCP/UDP的实现 TCP/UDP总结 网络基础概览 osi七层协议各层主要的协议 # 物理层传输电信号1010101010 # 数据链路层,以太网 ...

  3. 网络层协议与应用及传输层TCP/UDP协议

    网络层协议与应用及传输层TCP/UDP协议 目录 一.IP数据包格式 二.ICMP协议 三.ARP协议及ARP工作原理 四.TCP协议及常用端口号 五.UDP协议及常用端口号 一.IP数据包格式 网络 ...

  4. 什么是TCP/UDP协议?(超简单,一看就会)

    TCP/UDP协议做了什么? TCP/UDP协议处于计算机网络的第四层"传输层",负责传输数据包. 数据包怎么传?(UDP协议) TCP/UDP协议处于计算机网络的第四层" ...

  5. QQ--基于TCP/UDP协议的通讯原理

    QQ是一个基于TCP/UDP协议的通讯软件  发送消息的时候是UDP打洞,登陆的时候使用HTTP~因为登陆服务器其实就是一个HTTP服 务器,只不过不是常用的那些,那个服务器是腾讯自行开发的!   一 ...

  6. 【计算机网络】传输层 : 总结 ( TCP / UDP 协议 | 寻址与端口 | UDP 协议 | TCP 协议特点 | TCP 连接释放 | TCP 流量控制 | TCP 拥塞控制 ) ★★★

    文章目录 一.传输层 TCP / UDP 协议 ★ 二.寻址端口号 ★ 三.UDP 协议特点 四.UDP 协议首部格式 五.UDP 校验 六.TCP 协议 特点 ★ 七.TCP 报文段首部格式 八.T ...

  7. 最全的TCP/UDP 协议知识点整理

    关于计算机网络的基础知识,我前面写的两篇文章是入门文章,可以帮你构建一个计算机网络的基础架构,有了这个基础架构,后面的学习会很简单.下面是两篇文章的连接~~ 计算机网络体系结构与参考模型(1) 计算机 ...

  8. TCP/UDP协议总结与应用层常见协议及端口

    TCP/UDP协议总结与应用层常见协议及端口 1.TCP协议 TCP协议概述 TCP的应用场景 TCP的特点 TCP的报文格式 TCP三次握手 TCP四次挥手 2.UDP协议 UDP概述 UDP的应用 ...

  9. java聊天室小程序论文_在Java项目中利用continue与break制作一个聊天室小程序

    在Java项目中利用continue与break制作一个聊天室小程序 发布时间:2020-12-08 16:03:27 来源:亿速云 阅读:98 作者:Leah 在Java项目中利用continue与 ...

最新文章

  1. 算法应用与加速器系统架构的碰撞:AI软硬结合的方向怎么走?
  2. 用Spring Security实现后台登录及权限认证功能
  3. 中set无效是怎么回事_一起认识下,那些我们应该知道的mysql中的变量知识点
  4. java 语言循环总结
  5. Linux与时间相关的结构体及相关用法
  6. 如何为企业量身打造一套高可用系统?
  7. jsp连接sqlServer数据库教程、jsp连接sqlServer数据库报ClassNotFoundException异常
  8. 【Python实例第20讲】手写数字识别问题的K-Means聚类
  9. sql查询数据库所有表、字、注释
  10. 长ping命令返回结果输出为文本
  11. Typora自动生成标题编号(包含从二级标题开始的)
  12. Linux如何测试USB硬盘的读写速度
  13. 联想P340加显卡白屏,降级BIOS恢复正常。
  14. 计算机加域后桌面文件去哪里找,登录域桌面文件丢失
  15. 华硕无线网卡测试软件,华硕 AiMesh WiFi系统 无线回程测试
  16. 基于PHP美食食谱的外文翻译,翻译研究 | 中文菜谱英文翻译方法详解
  17. Install Ubuntu18.04.1 and Win7 on A53S
  18. Java - 什么是ORM?
  19. 使用FFMPEG将WebM转为MP4或MKV
  20. mui native.js 调用本地视频播放器

热门文章

  1. iOS系统音量控制——MPVolumeView
  2. Python将Excel表格按内容拆分为多个表格
  3. 51单片机蓝牙密码锁
  4. 莫比乌斯反演新手入门及练习题
  5. 海康威视-测试-面经(一面+hr面)
  6. Portraiture2023免费后期修图插件磨皮神器DR5
  7. 理想/沃尔沃“引领”「HUD+交互屏」潮流,哪些供应商领跑前装
  8. 日语学习资料汇总(可下载)
  9. C语言编程>第二十三周 ⑤ 请补充main函数,该函数的功能是:求1~100(不包括100)以内所有素数的平均值。
  10. SCI写作中常见的转折用法