《网络编程》小结

发布于:2022-12-31 ⋅ 阅读:(349) ⋅ 点赞:(0)

网络的分层模型

 应用层:用于自定义的网络数据协议

传输层:TCP/UDP协议

网络层:IPV4/IPV6,4G,5G 协议

物理层:一些硬件,网线、光纤、路由器

协议

协议是通信双方实现通信而制定的通话规则

目的:为了提高通信效率和安全性

 协议自己想怎么制定就怎么制定,但是使用别人的协议的时候必须遵守别人的协议规则

IP地址

作用:标识唯一主机

IPV4:4个字节             192.168.64.1

IPV6:6个字节              0-255.0-255.0-255.0-255

- A类地址 - 第1字节为网络地址,其他3个字节为主机地址。 - 第1字节的最高位固定为0 - `1.0.0.1 – 126.255.255.255`

- B类地址 - 第1字节和第2字节是网络地址,其他2个字节是主机地 址。 - 第1字节的前两位固定为10 - `128.0.0.1 – 191.255.255.255`

- C类地址 - 前3个字节是网络地址,最后1个字节是主机地址。 - 第1字节的前3位固定为110 - `192.0.0.1 – 223.255.255.255`

- D类地址(组播地址) - 不分网络地址和主机地址,第1字节的前4位固定为 1110 - `224.0.0.1 – 239.255.255.255`

端口:区分一个主机中的不同的网络进程,每一个网络进程都有一个唯一的端口号

端口号是一个短整型数据,长度为16位。具体分布:

- 系统端口:1~1023 (不推荐使用,系统网络进 程已经占用了)

- 注册端口:1024~49150 - 动态或私有端口:49151~65535(这是平常做实验可用 的端口号范围

网络字节序-----大端序

字节序: 大端字节序,低地址存放,高字节

                小端字节序,低地址存放,低字节

 通常,将最低有效位(即78)放在低地址的存储方式称 为小端序,反之即大端序。在单机编程中,字节序是系 统内部的存储细节,与程序无关。但在网络编程中,由 于数据是在两台不同的机器中传输和表达,因此如果字 节序不一致,则会出现牛头不对马嘴的现象。 解决这一困境的办法是,将网络中的数据,统一为某种 固定的字节序,比如大端序。这样一来,凡是从主机往 外发的数据,一律转换为大端序,凡是从网络接收的数 据,也一律是大端序,网络字节序屏蔽了通信双方的具 体细节,从而使得双方通信成为可能。

子网与公网和外网

内网:(子网)局域网

内网又称局域网(LAN),是指在某一区域内由多台计算机 以及网络设备构成的网络,比如校园网、政府网等,一般方 圆几公里。

公网: Internet 网由运营商提供。 (实现远程通信)

外网: 需要翻墙工具, 梯子,飞机 ....

什么是TCP

TCP 通信还会被冠以 可靠传输协议 的头衔。但请注意,这里的可靠并非指发出去的数据对方一定能收到(这是不可能的),而仅指TCP能使发送方可靠地知道对方是否收到了数据。

TCP基本特征

  • 有连接:通信双方需要事先连接成功,方可传输数据

  • 有确认:一方收到对端的任何数据,都会给另一方发回执确认

  • 保证数据有序、不重复、丢失会重发

  • 如果网络拥堵,会自动调节发送量

  • 采用帧异步的流式通信方式(即通信双方每次的收发数据量不必相等)

简单来讲,TCP 类似于打电话,说话前需要花一定的时间接通电话,等到对方接听了之后双方才能开始通信,通信的过程中每个数据的传送,接收方都会给发送方回执确认,断开的时候也会互相通知以便于释放各自相关的资源。可以看出来,TCP 相对于 UDP 而言资源开销更大,提供更丰富的功能,TCP适合用在如下情形:

  • 传输质量要求较高,不能丢失数据

  • 大数据量的通信,以至于通信前后的连接和断开的开销可以忽略不计

  • 用户登录、账户管理等相关的功能

TCP流程图

TCP服务器创建流程

1、socket  创建服务器对象

int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);  

2、bind    绑定服务器地址信息

#include <sys/types.h>
#include <sys/socket.h>

int bind(int socket, const struct sockaddr *addr, socklen_t addrlen);
                    
                  sockfd:服务器对象 
                  addr:服务器地址   
                  addrlen:服务器地址长度 
                  返回值: 成功   0
                         失败  -1  

3.listen 设置为监听模式

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int listen(int sockfd, int backlog);

			sockfd:服务器对象 
            backlog:同时支持多少个用户链接。 backlog 最大值可设至128。
            返回值: 成功   0 
                    失败  -1

4、accept接受链接请求

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
	    sockfd:服务器对象  
        addr:对方(发起请求者)IP地址信息
        addrlen:对方(发起请求者)IP地址的大小  
        返回值: 返回一个 新的socket  
               失败    -1 

TCP客户端创建流程

1、sockect 创建通信对象

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int socket(int domain, int type, int protocol);
	        domain:网络协议      AF_INET           IPv4 Internet protocols          ip(7)
	        type:传输协议      SOCK_STREAM       TCP
            protocol:属性默认为     0                即可
            返回值: 成功  网络文件描述符  
     	            失败  -1 
     
    
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);  

2、connect   连接服务器(重点)

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	     sockfd:网络文件描述符 
         addr:需要连接的服务器地址信息  (你要打电话给某人必须要知道他的电话号码)  
         addrlen:地址长度 
         返回值:成功  0  
               失败  -1 
//服务器地址结构体       
struct sockaddr_in {
 sa_family_t    sin_family; /* 服务器地址类型: AF_INET->IPV4类型*/
 in_port_t      sin_port;   /* 服务器的端口号 */
 struct in_addr sin_addr;   /* 服务器的IP地址 */
};

/* Internet address. */
struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};              
   

一般的IP地址都是以点分制编写的如:192.168.64.1 
    
#include <arpa/inet.h>
把字符串IP转换为  uint32_t IP  
in_addr_t inet_addr(const char *cp);  

把uint32_t IP转换为字符串 IP  
char *inet_ntoa(struct in_addr in);  


网络通信都采用大端序  
uint16_t htons(uint16_t hostshort); //把本地序转换为网序 
uint16_t ntohs(uint16_t netshort);  //把网络序转换为本地序






demo连接 ip:192.168.64.1端口:2333的服务器: 
struct sockaddr_in ser_addr; 
ser_addr.sin_family =  AF_INET; //IPV4  
ser_addr.sin_port   =  htons(2333);  //把本地序转换为网络序 
ser_addr.sin_addr.s_addr =  inet_addr("192.168.64.1");  
int ret=connect(tcp_socket,(struct sockaddr *)&ser_addr,sizeof(ser_addr));
if(ret < 0)
{
    perror("");
}else 
{
    printf("连接成功\n");
}

3、read/write读写  或者 send/recv 发送接收


ssize_t send(int sockfd, const void *buf, size_t len, int flags);
			   sockfd: 需要发送的网络文件描述符 
               buf: 数据缓存区 
               len: 数据的大小  
               flags:一般设0


 ssize_t recv(int sockfd, void *buf, size_t len, int flags);
			     sockfd: 需要发送的网络文件描述符 
                  buf: 数据缓存区 
                  len: 数据的大小  
                  flags:一般设0



参数flags一般设0,其他数值定义如下
MSG_OOB 传送的数据以out-of-band 送出。
MSG_DONTROUTE 取消路由表查询
MSG_DONTWAIT 设置为不阻塞 
MSG_NOSIGNAL 此动作不愿被SIGPIPE 信号中断。

UDP

什么是UDP:UDP 通信还会被冠以不可靠的头衔。这里的不可靠指的是:无法可靠地得知对方是否收到数据。

特征:

1、无连接:通信双方不需要事先连接

2、无确认:收到数据不发给对方发回执确认

3、数据丢失 后不会重发

4、采用帧同步数据报信方式(双方每次的收发数据量相等)

UDP类似于寄信,寄信人无法是否确认对方是否收到信。但是UDP无需连接、无需确认、无需缓冲区、无需分包序列号,所以它的效率比较高。

UDP适用于发小数据文件(如:对DNS服务器进行IP地址查询时)

UDP通信流程图

UDP单播设计

特点:指定IP和端口,进行一对一通信。

发送端

1、创建UDP通信对象

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
//创建UDP 通信对象 
int  udp_socket = socket(AF_INET, SOCK_DGRAM, 0);

2、发送UDP数据报

ssize_t sendto(int sockfd, //UDP 通信对象socket 
                const void *buf,//数据缓存地址 
                size_t len, //数据大小 
                int flags, //属性默认为 0 即可 
                const struct sockaddr *dest_addr, //目标地址 (接收信息主机的地址)
                socklen_t addrlen);//地址长度 
		返回值: 成功  发送的字节数 
               失败  -1  
            
  
const struct sockaddr *dest_addr 的设置如下: 

struct sockaddr_in dest_addr;
dest_addr.sin_family=AF_INET; //设置网络协议 
dest_addr.sin_port=htons(端口);
dest_addr.sin_addr.s_addr=inet_addr(IP地址);


demo : 发送一个UDP数据报 
sendto(udp_socket,"hello",5,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr)); 

接收端

1、创建UDP通信socket

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
//创建UDP 通信对象 
int  udp_socket = socket(AF_INET, SOCK_DGRAM, 0);

2.绑定接收端的地址信息

struct sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(端口);
server_addr.sin_addr.s_addr=INADDR_ANY; //所有网卡地址 
bind(udp_socket,(struct sockaddr *)&server_addr,sizeof(server_addr));

3.接收UDP 数据报

ssize_t recvfrom(int sockfd, //UDP 通信对象socket  
                 void *buf,//接收数据缓存地址  
                 size_t len, //数据长度 
                 int flags, //属性默认为0  
                 struct sockaddr *src_addr, //数据发送者的IP地址信息 
                 socklen_t *addrlen);//IP地址信息长度

demo:只接收数据不获取IP 
    char buf[1024]={0};
    recvfrom(udp_socket,buf,1024,0,NULL,NULL);

UDP组播设计

特点:加入小组的都可以接收到数据

1、创建UDP通信对象

int udp_socket = socket(AF_INET,SOCK_DGRAM,0);

2、绑定UDP通信对象

struct sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(端口);
server_addr.sin_addr.s_addr=INADDR_ANY; //所有网卡地址 
DR_ANY; //所有网卡地址 
bind(udp_socket,(struct sockaddr *)&server_addr,sizeof(server_addr));

3、加入组播

struct ip_mreq a;
bzero(&a, sizeof(a));
a.imr_interface.s_addr = INADDR_ANY; //所有网卡地址加入组播 
a.imr_multiaddr.s_addr = inet_addr("224.10.10.10"); // 指定多播地址
//开启组播功能 
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &a, sizeof(a));


————————————————————————————————————————————————————————————————————
//组播结构体 
struct in_addr
{
  in_addr_t s_addr;
};

struct ip_mreq
{
  struct in_addr imr_interface;	/* 需要加入组播的IP地址 */
  struct in_addr imr_multiaddr;	/* 组播地址(D类地址) */
};

D类地址: 224.0.0.1 ~ 239.255.255.255  

4、往组播地址发送数据

struct sockaddr_in arry_addr;
arry_addr.sin_family=AF_INET;
arry_addr.sin_port=htons(8888);
arry_addr.sin_addr.s_addr=inet_addr("224.10.10.10"); //所有网卡地址 
sendto(udp_socket,buf,strlen(buf),0,(struct sockaddr *)&arry_addr,sizeof(arry_addr));




UDP广播设计

特点:在同一个(网络地址)网段中的所有主机都可以接收到数据。

1、创建UDP通信对象

int  udp_socket = socket(AF_INET, SOCK_DGRAM, 0);

2、开启广播功能

int on=1; //开启
int ret =  setsockopt(udp_socket,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)); 
if(ret < 0)
{
    perror("广播开启失败:");
    return -1; 
}else 
{
    printf("广播开启成功\n");
}

3、发送数据

//设置广播地址 
struct sockaddr_in dest_addr;
dest_addr.sin_family=AF_INET; //设置网络协议 
dest_addr.sin_port=htons(6666); //所有处于192.168.64网段且,端口为 6666 的进程都可以收到数dest_addr.sin_addr.s_addr=inet_addr("192.168.64.255"); //设置广播地址 

//发送一个UDP 广播数据报
sendto(udp_socket,"hello",5,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr)); 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到