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

网络编程 总结二

一、TCP

TCP模型

1. TCP搭建相关函数:

 套接字Socket

 1)Socket函数:

2)bind

 3)listen

 4)accept

 5)recv

 注意:

1> TCP中的recv 可以替换成read;         2>TCP中的recv可以替换成recvfrom

6)send

  注意:

1> TCP中的send 可以替换成 write;         2>TCP中的 send 可以替换成 sendto

7)connet

 客户端:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>#define ERR_MSG(msg) do{\fprintf(stderr,"liine %d",__LINE__);\perror(msg);\
}while(0)#define IP "192.168.8.77"  //本机IP 
#define PORT 6666          // 1024-49151int main(int argc, const char *argv[])
{//创建流式套接字int cfd = socket(AF_INET,SOCK_STREAM,0);if(cfd<0){ERR_MSG("socket");return -1;}printf("cfd=%d\n",cfd);//允许端口快速重用int reuse=1;if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0){ERR_MSG("setsockopt");return -1;}//填充地址信息结构体//真是的地址信息结构体根据地址族制定  AF_INET: man 7 ipstruct sockaddr_in sin;sin.sin_family = AF_INET;//必须填 AF_INETsin.sin_port = htons(PORT);//端口号, 1024-49151sin.sin_addr.s_addr = inet_addr(IP);//本机IP,ifconfig//连接服务器if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("connet");return -1;}printf("connect  sucess __%d__\n",__LINE__);char buf[128]="";ssize_t res=0;while(1){bzero(buf,sizeof(buf));printf("请输入数据>>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]=0;//发送if(send(cfd,buf,sizeof(buf),0)<0){ERR_MSG("send");return -1;}printf("send sucess\n");//接收bzero(buf,sizeof(buf));res=recv(cfd,buf,sizeof(buf),0);if(res<0){ERR_MSG("recv");return -1;}else if(0==res){printf("cfd=%d 服务器下线 __%d__\n",	cfd,__LINE__);break;}printf("cfd=%d %s __%d__\n",cfd,buf,__LINE__);}close(cfd);return 0;
}

服务器:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>#define ERR_MSG(msg) do{\fprintf(stderr,"liine %d",__LINE__);\perror(msg);\
}while(0)#define IP "192.168.8.77"  //本机IP 
#define PORT 6666          // 1024-49151int main(int argc, const char *argv[])
{//创建流式套接字int sfd = socket(AF_INET,SOCK_STREAM,0);if(sfd<0){ERR_MSG("socket");return -1;}printf("sfd=%d\n",sfd);//允许端口快速重用int reuse=1;if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0){ERR_MSG("setsockopt");return -1;}//填充地址信息结构体//真是的地址信息结构体根据地址族制定  AF_INET: man 7 ipstruct sockaddr_in sin;sin.sin_family = AF_INET;//必须填 AF_INETsin.sin_port = htons(PORT);//端口号, 1024-49151sin.sin_addr.s_addr = inet_addr(IP);//本机IP,ifconfig//将IP和端口号绑定到套接字上if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("bind");return -1;}printf("bind sucess __%d__\n",__LINE__);//将套接字设置为被动监听状态,监听是否有客户端连接成功if(listen(sfd,128)<0){ERR_MSG("listen");return -1;}printf("listen success __%d__\n",__LINE__);struct sockaddr_in cin;        // 存储连接成功的客户端地址信息  socklen_t addrlen = sizeof(cin);//阻塞函数,从已完成连接的队列头中获取一个客户端信息//该文件描述符才是与客户端通信的文件描述符int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);if(newfd<0){ERR_MSG("accept");return -1;}printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);char buf[128]="";ssize_t res=0;while(1){//接收res=recv(newfd,buf,sizeof(buf),0);if(res<0){ERR_MSG("recv");return -1;}else if(0==res){printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);break;}printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);//发送strcat(buf,"*_*");if(send(newfd,buf,sizeof(buf),0)<0){ERR_MSG("send");return -1;}printf("send sucess\n");}close(newfd);close(sfd);return 0;
}

二、UDP

UDP模型

 1. UDP相关函数

1)socket

2)bind

3)recvfrom

 4)sendto

 客户端:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>#define ERR_MSG(msg) do{\fprintf(stderr,"line:%d",__LINE__);\perror(msg);\
}while(0)#define SER_IP "192.168.8.77" //本机IP 
#define SER_PORT 6666#define CLI_IP "192.168.8.77" //本机IP 
#define CLI_PORT 8888int main(int argc, const char *argv[])
{//创建报式套接字int cfd = socket(AF_INET, SOCK_DGRAM,0);if(cfd<0){ERR_MSG("socket");return -1;}
//*****************************************************	struct sockaddr_in cin;cin.sin_family  = AF_INET;      //必须填AF_INETcin.sin_port = htons(CLI_PORT);     //端口号的网络字节符cin.sin_addr.s_addr = inet_addr(CLI_IP);if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin))<0){ERR_MSG("bind");return -1;}printf("client bind success\n");
//********************************************************//填充服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family  = AF_INET;      //必须填AF_INETsin.sin_port = htons(SER_PORT);     //端口号的网络字节符sin.sin_addr.s_addr = inet_addr(SER_IP);struct sockaddr_in rcvaddr;//存储数据包是从哪里来的socklen_t addrlen = sizeof(rcvaddr);char buf[128]="";ssize_t res =0;while(1){bzero(buf,sizeof(buf));printf("请输入数据>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]=0;//发送数据,发送给服务器if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("sendto");return -1;}printf("发送数据\n");//接收数据,必须接收数据包的发送方地址信息res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&rcvaddr,&addrlen);if(res<0){ERR_MSG("recvfrom");return -1;}printf("[%s : %d]: %s\n",inet_ntoa(rcvaddr.sin_addr), ntohs(rcvaddr.sin_port),buf);}//关闭文件描述符close(cfd);return 0;
}

服务器:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>#define ERR_MSG(msg) do{\fprintf(stderr,"line%d",__LINE__);\perror(msg);\
}while(0)#define IP "192.168.8.77" //本机IP 
#define PORT 6666int main(int argc, const char *argv[])
{//创建报式套接字int sfd = socket(AF_INET, SOCK_DGRAM,0);if(sfd<0){ERR_MSG("socket");return -1;}//填充服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family  = AF_INET;      //必须填AF_INETsin.sin_port = htons(PORT);     //端口号的网络字节符sin.sin_addr.s_addr = inet_addr(IP);//绑定 必须绑定if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("bind");return -1;}struct sockaddr_in cin;//存储数据包是从哪里来的socklen_t addrlen = sizeof(cin);char buf[128]="";ssize_t res =0;while(1){bzero(buf,sizeof(buf));//接收数据,必须接收数据包的发送方地址信息res=recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen);if(res<0){ERR_MSG("recvfrom");return -1;}printf("[%s : %d]: %s\n",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port),buf);strcat(buf,"*_*");if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,sizeof(cin))<0){ERR_MSG("sendto");return -1;}printf("发送成功\n");}//关闭文件描述符close(sfd);return 0;
}

2.UDP中的connect 函数(重点

1>TCP中的connect函数会造成三次握手,将client 与 server 连接;UDP中的connect 仅仅是将对端的 IP 和端口号记录到内核中。此时UDP只能与记录的对端进行通信。

2>TCP中的connect 函数只能调用一次;UDP中的可以调用多次 connect 函数,刷新内核中对端的IP地址和端口,如果想要清空内核中对端的地址信息,则可以将sin_family 成员修改成AF_UNSPEC

3>当UDP采用connect 方式收发报文后,可以调用 send write 函数 也可以调用sendto函数。

1> sendto ( sd,buf,sizeof ( buf ) , NULL , 0 );

recvfrom 在后面的地址信息结构体填NULL 的时候,可以替换成 recv  read

2> recvfrom ( sockfd , buf, len , flags , NULL ,NULL );

 UDP调用connect 函数的优点:

1>提升传输效率:

a.  不调用connect :将对端的地址信息填充到内核--> 发送报文--->清空内核信息--->将对端的地址信息填充到内核-->发送报文--->清空内核信息

b.  调用了connect :将对端的地址信息填充到内核--> 发送报文--> 发送报文--> 发送报文--->清空内核信息

2>增加传输的稳定性:

a. 调用connect 函数的UDP通信,可以防止AB进程在数据传输过程中收到C进程消息,造成传输错误

3. UDP多点通信

【1】网络属性

setsockopt / getsockopt

 

 【2】多点通信

1. 单播

1>主机之间一对一的通信模式,交换机以及路由器对数据只进行转发,不复制

2>每次只有两个实体相互通信,发送端和接收端都是唯一确定的

2. 广播

1>主机之间一对多的通信模式,网络对其中的每一台主机发出的信号都进行无条件复制并转发

2>在同一个局域网下的所有主机都可以接收到广播信息

3>禁止广播数据穿过路由器,防止广播数据影响大面积主机

4>广播数据不需要应答,只有UDP才能做广播

5>广播地址:有效网络号+ 全是1 的主机号

1)广播的发送端(类似客户端)

1> socket    创建报式套接字    ;  bind  非必须绑定

2>setsockopt 设置允许广播:level: SOL_SOCKET   optname: SO_BROADCAST

3> 指定接收端的地址信息结构体

                a. IP :  填写广播IP

                b. PORT : 与接收端填充的一致即可

4> sendto    发送广播数据

2)广播的接收端(类似服务器)

1> socket    创建报式套接字    ;  bind  必须绑定

2>填充接收端自身的地址信息结构体

  a. IP :  填写广播IP :有效网络号 + 全是 1 的主机号

                调用bind 函数后,会将本机所有可用IP 地址都绑定到套接字上

                b. PORT : 与发送端填充的一致即可

3> recvfrom    接收广播数据

3. 组播(多播组)

1)组播的发送端(类似客户端)

1>socket    创建报式套接字    ;  bind 非必须绑定

2> 指定接收端的地址信息结构体

  a. IP :  填写组播IP  (224.0.0.0~239.255.255.255,与接收方填充一致)

                b. PORT : 与接收端填充的一致即可

3> sendto    发送组播数据

2)组播的接收端(类似服务器)

1> socket    创建报式套接字    ;  bind  必须绑定

2>setsockopt 加入多播组:level :  IPPROTO_IP     OPTNAME : IP_ADD_MEMBERSHIP   

3>填充接收端自身的地址信息结构体

          a. IP :  填写组播IP 

                b. PORT : 与发送端填充的一致即可

4> recvfrom    接收组播数据

多播snd:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>#define ERR_MSG(msg) do{\fprintf(stderr,"line:%d",__LINE__);\perror(msg);\
}while(0)#define GRP_IP "243.1.2.3" //本机IP 
#define PORT 6666int main(int argc, const char *argv[])
{//创建报式套接字int cfd = socket(AF_INET, SOCK_DGRAM,0);if(cfd<0){ERR_MSG("socket");return -1;}//填充服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family  = AF_INET;      //必须填AF_INETsin.sin_port = htons(PORT);     //端口号的网络字节符sin.sin_addr.s_addr = inet_addr(GRP_IP);char buf[128]="";ssize_t res =0;while(1){bzero(buf,sizeof(buf));printf("请输入数据>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]=0;//发送数据,发送给服务器if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("sendto");return -1;}printf("发送数据\n");}//关闭文件描述符close(cfd);return 0;
}

多播rcv:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>#define ERR_MSG(msg) do{\fprintf(stderr,"line%d",__LINE__);\perror(msg);\
}while(0)#define IP "192.168.0.79" //本机IP 
#define GRP_IP "224.1.2.3" //组播IP 
#define PORT 6666int main(int argc, const char *argv[])
{//创建报式套接字int sfd = socket(AF_INET, SOCK_DGRAM,0);if(sfd<0){ERR_MSG("socket");return -1;}//加入多播组struct ip_mreqn mq;mq.imr_multiaddr.s_addr = inet_addr(GRP_IP);//组播IPmq.imr_address.s_addr = inet_addr(IP);mq.imr_ifindex=2;if(setsockopt(sfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mq,sizeof(mq))<0){perror("setsockopt");return -1;}//填充服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family  = AF_INET;      //必须填AF_INETsin.sin_port = htons(PORT);     //端口号的网络字节符sin.sin_addr.s_addr = inet_addr(GRP_IP);//绑定 必须绑定if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("bind");return -1;}struct sockaddr_in cin;//存储数据包是从哪里来的socklen_t addrlen = sizeof(cin);char buf[128]="";ssize_t res =0;while(1){bzero(buf,sizeof(buf));//接收数据,必须接收数据包的发送方地址信息res=recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen);if(res<0){ERR_MSG("recvfrom");return -1;}printf("[%s : %d]: %s\n",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port),buf);}//关闭文件描述符close(sfd);return 0;
}

三、TFTP协议

1)TFTP协议概述:简单文件传输协议适用于在网络上进行文件传输的一套标准协议,使用UDP传输

特点:应用层协议;基于UDP协议实现

数据传输模式:

                     octet: 二进制模式(常用)

                     mail : 已经不在支持

2)TFTP下载模型

 3)TFTP通信过程总结

1>服务器在69号端口等待客户端的请求

2>服务器若批准请求,则使用临时端口与客户端进行通信

3>每隔数据包的编号都有变化(从1开始)

4>每隔数据包都要得到ACK的确认,如果出现超时,则需要重新发送最后的数据包或ACK包

5>数据长度以512Byte传输,小于512Byte的数据意味着数据传输结束

 4)TFTP协议分析

 代码:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>#define ERR_MSG(msg) do{\fprintf(stderr,"line:%d",__LINE__);\perror(msg);\
}while(0)#define SER_IP "192.168.171.1" //本机IP 
#define SER_PORT 69int do_download(int cfd, struct sockaddr_in sin)
{//下载请求char filename[20]="";char buf[516]={0};printf("请输入要下载的文件名>>");scanf("%s",filename);while(getchar()!=10);short*p1 = (short*)buf;*p1 = htons(1);char*p2 = buf+2;strcpy(p2,filename);char*p3 = p2+strlen(p2);char*p4 = p3+1;strcpy(p4,"octet");int size=strlen(p2)+strlen(p4)+4;//发送下载请求协议if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("sendto");return -1;}printf("发送成功\n");int fd=-1;socklen_t  addrlen=sizeof(sin);ssize_t res =0;unsigned short num=0;int ret=0;	while(1){bzero(buf,sizeof(buf));//接收数据,必须接收数据包的发送方地址信息res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);if(res<0){ERR_MSG("recvfrom");ret=-1;break;}if(buf[1]==3){if(htons(num+1)==*(unsigned short*)(buf+2)){//组数据包给服务器num++;if(1==ntohs(*(unsigned short*)(buf+2))){fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664);if(fd<0){ERR_MSG("open");return -1;}}if(write(fd,buf+4,res-4)<0){ERR_MSG("write");ret=-1;break;}//回复ACK,由于ACK包和数据包前四个字节只有操作码不一致//直接修改数据包的操作码buf[1]=4;if(sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("sendto");ret =-1;break;}if(res-4<512){printf("文件:%s 上传完毕\n",filename);break;}}}else if(buf[1]==5)//错误包{fprintf(stderr,"DOWNLOAD_EROR: %d: %s\n",ntohs(*(unsigned short*)(buf+2)),buf+4);break;}}close(fd);return ret;
}int main(int argc, const char *argv[])
{//创建报式套接字int cfd = socket(AF_INET, SOCK_DGRAM,0);if(cfd<0){ERR_MSG("socket");return -1;}//填充服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family  = AF_INET;      //必须填AF_INETsin.sin_port = htons(SER_PORT);     //端口号的网络字节符sin.sin_addr.s_addr = inet_addr(SER_IP);char c=0;while(1){system("clear");printf("*****************\n");printf("******1.下载*****\n");printf("******2.上传*****\n");printf("******3.退出*****\n");printf("*****************\n");c=getchar();while(getchar()!=10);switch(c){case'1':do_download(cfd,sin);break;case'2':break;case'3':goto END;break;default:printf("输入错误,请重新输入\n");}printf("请输入任意字符清屏>>>");while(getchar()!=10);}END:close(cfd);return 0;
}

http://www.lryc.cn/news/65440.html

相关文章:

  • 消息称苹果Type-C口充电未设MFi限制,iOS17将更新Find My服务
  • 设计模式——工厂模式(简单工厂、工厂方法、抽象工厂)
  • 《C语言技术体系》 学习路线总目录 + 思维导图
  • 数字图像处理简答题
  • 【Java校招面试】基础知识(五)——GC
  • 使用CMake调用Makefile 项目
  • 快速傅里叶变换FFT学习笔记
  • 如何下载安装驱动
  • 鸿蒙Hi3861学习四-Huawei LiteOS介绍
  • Vue核心 收集表单数据 过滤器
  • 华为EC6108V9E/EC6108V9I_rk3228_安卓4.4.4_通刷_卡刷固件包
  • 数字化转型导师坚鹏:面向数字化转型的大数据顶层设计实践
  • day27_mysql
  • QwtPlotCurve使用说明
  • JS逆向 -- 某平台登录加密分析
  • 一分钟快速实现Flask框架的蓝图和视图
  • Mysql 约束练习【第13章_约束】
  • java调用cmd命令
  • Qt音视频开发36-超时检测和自动重连的设计
  • Reactor 第九篇 WebFlux重构个人中心,效果显著
  • Vben Admin 自学记录 —— Drawer组件的基本使用及练习(持续更新中...)
  • Android 9.0 根据包名默认授予app悬浮窗权限
  • Swift中Data,String,[UInt8]的相互转换(6种互相转换)
  • 【微软Bing王炸更新】无需等待,人人可用,答案图文并茂,太牛了
  • 腾讯云的cdn怎么配置|腾讯云CDN配置教程
  • 数据结构入门-顺序表链表
  • 【AWS入门】AWS Lamda
  • 牛客刷SQL题Day5
  • 【Errors】【计算机图形学】A-SDF复现的一点纠正记录
  • Dockerfile创建镜像文件