Linux C 网络编程概述

网络编程

  • 计算机网络
    • 概述
    • 分类
    • 网络体系结构
    • 通信协议
    • 通信流程
      • 网络通信帧格式
        • 以太网帧格式分析
        • ARP 协议分析
        • IP 数据报分析
          • IP分类
          • IP 分配
          • 子网掩码
        • TCP 段分析
      • TCP三次握手协议 ⭐
      • TCP四次挥手协议 ⭐
  • TCP编程
    • 基于 TCP 客户端编程-步骤说明
    • 基于 TCP 服务器端编程-步骤说明
    • 基于 TCP 服务端/客户端编程例子⭐
    • 基于 TCP 服务端/客户端编程详细案例⭐
    • 函数
      • 创建套接字  socket
      • 绑定函数  bind
        • 大小端排序转换函数
        • 地址格式转换函数
      • 监听  listen
      • 等待客户端连接  accept
      • 连接服务器   connect
      • 发送函数  send
      • 接收函数  recv
  • NAT映射
    • 概述
    • NAT 的优缺点
  • 内网穿透(打洞)技术
  • UDP编程
    • 概念
    • 通信流程
    • 基于 UDP 客户端编程思路
    • 基于 UDP 服务器端编程思路
    • 基于UDP 客户端/服务端编程例子⭐
    • 函数
      • 发送函数  sendto
      • 接收函数  recvfrom
    • UDP广播
      • 概念
      • 广播特点
      • 广播地址
  • 网络编程服务器模型
    • 回射服务器
    • 迭代服务器
    • 并发服务器

计算机网络

概述

  计算机网络是指将不同地理位置,具有独立功能的多台计算机及网络设备通过通信线路(包括传输介质和网络设备连接起来),在网络操作系统、网络管理软件及网络通信协议的共同管理和协调下实现资源共享和信息传递的计算机系统。

分类

1 ) 地理范围:广域网 WAN、城域网 MAN、局域网 LAN、个人区域网 PAN。
2 ) 按拓扑结构:星型拓扑结构、总线型拓扑结构、环形拓扑结构、网状拓扑结构、混合拓扑结构。
3 ) 按网络使用者分类:公用网、专用网。
  局域网(LoxalAreaNetwork,LAN)是指范围在几百米到十几公里内办公楼群或校园内的计算机相互连接所构成的计算机网络。计算机局域网被广泛应用于连接校园、工厂以及机关的个人计算机或工作站,以利于个人计算机或工作站之间共享资源和数据通信。
  城域网(MetropolitanAreaNetwork,MAN)所采用的技术基本上与局域网相类似,只是规模上要大一些。城域网既可以覆盖相距不远的几栋办公楼,也可以覆盖一个城市;既可以是私人网,也可以是公用网。城域网既可以支持数据和话音传输,也可以与有线电视相连。城域网一般只包含一到两根电缆,没有交换设备,因而其设计就比较简单。
  广域网(WidoAreaNetwork,WAN)通常跨接很大的物理范围,如一个国家。广域网包含很多用来运行用户应用程序的机器集合,我们通常把这些机器叫做主机;把这些主机连接在一起的是通信子网(communicationsubnet)。通信子网的任务是在主机之间传送报文。将计算机网络中的纯通信部分的子网与应用部分的主机分离开来,可以大大简化网络的设计。

网络体系结构

在这里插入图片描述
  ISO 制定的 OSI 参考模型的过于庞大、复杂招致了许多批评。因此简化ISO的TCP/IP应运而生。
在这里插入图片描述

通信协议

TCP/IP:英文(Transmission Control Protocol/Internet Protocol)的缩写,传输控制协议/网际协议。
Telnet:是 TCP/IP 协议族中的一员,是 Internet 远程登陆服务的标准协议。
FTP:(文件传输协议)用于在网络上进行文件传输的一套标准协议,使用客户/服务器模式。
TCP:(传输控制协议) 为应用程序提供可靠的通信连接。适合于一次传输大批数据的情况。并适用于要求高的应用程序。
UDP:(用户数据包协议)提供了无连接通信,且不对传送包进行可靠的保证。适合于一次传输少量数据。
ICMP:(网络控制消息协议)用于发送报告有关数据包的传送错误的协议。
IGMP:(网络组管理协议)被 IP 主机用来向本地多路广播路由器报告主机组成员的协议。
IP:(网际互联协议)负责在主机和网络之间寻址和路由数据包。
ARP:(地址转换协议)用于获得同一物理网络中的硬件主机地址。
MPLS:(多协议标签交换)很有发展前景的下一代网络协议。

通信流程

网络通信帧格式

  数据包在以太网物理介质上传播之前必须封装头部和尾部信息。封装后的数据包称为称为数据帧,数据帧中封装的信息决定了数据如何传输。以太网上传输的数据帧有两种格式,选择哪种格式由 TCP/IP 协议簇中的网络层决定。
  网络通信中有两种数据帧格式:第一种是上世纪 80 年代初提出的 DIX v2 格式,即 Ethernet II 帧格式。Ethernet II 后来被 IEEE 802 标准接纳,并写进了 IEEE 802.3x-1997 的 3.2.6 节。以太网中大多数的数据帧使用的是 Ethernet II格式。本课程主要研究 Ethernet(以太网帧格式)在网络中传输过程。
网络通信帧格式

以太网帧格式分析

在这里插入图片描述

ARP 协议分析

在这里插入图片描述

IP 数据报分析

在这里插入图片描述

IP分类

  按照 IP 版本分类:IPv4、IPv6。IPv4 的地址位数为 32 位,也就是最多有 2 的 32 次方(42 亿)的电脑可以连接: 近十年来由于互联网的蓬勃发展,IP 地址的需求量愈来愈大,导致 IPv4 定义的有限地址空间将被耗尽,地址空间的不足必将妨碍互联网的进一步发展。为了扩大地址空间,拟通过 IPv6 重新定义地址空间。IPv6 采用 128 位地址空间长度,几乎可以不受限制地提供地址。
  按照状态分类:静态 IP 与动态 IP。动态 IP 需要在连接网络时自动获取 IP 地址以供用户正常上网,而静态 IP 是 ISP 在装机时分配给用户的 IP 地址,可以直接连接上网,不需要获取 IP 地址。
  按照 IP 身份分类:公有 IP 与私有 IP。公有 IP:指以公网连接 Internet 上的非保留地址。私有 IP:是在本地局域网上的 IP。
  每个 IP 地址都被分为两个部分即网络地址和主机地址。这样做的目的是为了在路由器转发数据包时更方便的寻址。网络位是用来确定网络的,就相当于你生活在哪个区域。主机位就是每一台电脑所用的 IP 地址,就相当于你所在区域有多少人,每个人的固定住所。

IP 分配

全为 0 表示任意 全为 1 表示广播
A 类地址范围:1.0.0.1—126.155.255.254
A 类:0xxxxxxx.hhhhhhhh.hhhhhhhh.hhhhhhhh  2^24-2=16777214;
B 类地址范围:128.0.0.1—191.255.255.254
B 类:10xxxxxx. xxxxxxxx.hhhhhhhh.hhhhhhhh   2^16-2=65534;
C 类地址范围:192.0.0.1—223.255.255.254
C 类:110xxxxx.xxxxxxxx.xxxxxxxx.hhhhhhhh   2^8-2=254;
D 类地址范围:224.0.0.1—239.255.255.254
E 类地址范围:240.0.0.1—255.255.255.254

  在Linux系统中可以使用 ifconfig 指令先查看当前网络 IP 地址信息。
  也可以使用 ifconfig ens33 指令修改 IP,例如:ifconfig ens33 192.168.1.64 netmask 255.255.255.0
  最后可以使用 ping + ip 命令ping自己查看是否重置成功。也可以ping命令查看是否与目标主机连接。

子网掩码

  子网掩码为网络掩码、地址掩码、子网络遮罩,一种用来指明一个 IP 地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合 IP 地址一起使用。子网掩码只有一个作用,将某个 IP 地址划分成网络地址和主机地址两部分。子网掩码为一个 32 位地址,用于屏蔽 IP 地址的一部分以区别网络标识和主机标识,并说明该 IP 地址是在局域网上,还是在广域网上。

TCP 段分析

在这里插入图片描述

TCP三次握手协议 ⭐

在这里插入图片描述

TCP四次挥手协议 ⭐

在这里插入图片描述

TCP编程

  套接字是操作系统内核中的一个数据结构,它是网络的节点进行相互通信的门户,它是网络进程的 ID。
  端口号是具有网络功能的应用软件的标识号。端口是一个软件结构,被客户程序或服务程序用来发送和接收数据,一台服务器(或计算机)有 256*256 个端口。

基于 TCP 客户端编程-步骤说明

1.创建通信套接字:socket;
2.编写服务器地址信息(IP 端口 协议 TCP);
3.连接服务器:connect
4.发送信息/接收信息;send/rec | write/read
5.关闭通信套接字;close

基于 TCP 服务器端编程-步骤说明

1.创建监听套接字:socket
2.编写服务器地址信息;(IP 端口 协议 TCP);
3.将服务器地址信息与监听套接字绑定:bind;
4.开始监听:listen
5.等待客户端连接:accept(阻塞等待)
//三次握手
6.发送信息/接收信息 read/write
7.关闭通信套接字:close

在这里插入图片描述

基于 TCP 服务端/客户端编程例子⭐

客户端:具备基础通信功能

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <semaphore.h>
typedef struct sockaddr  SA;
typedef struct sockaddr_in  SIN;
#define MAXBACKLOG   100int Socket(int domain,int type,int protocol);
int Connect(int sockfd,struct sockaddr * serv_addr,int addrlen);
void *son_fun(void * arg);int main(int argc,char *argv[])
{	pthread_t id;//建立监听套接字int socketfd = Socket(AF_INET,SOCK_STREAM,0);//connectSIN   serverinfo;serverinfo.sin_family = AF_INET;serverinfo.sin_port   = htons(atoi(argv[2]));serverinfo.sin_addr.s_addr =  inet_addr(argv[1]);int addrlen = sizeof(SIN);Connect(socketfd,(SA*)&serverinfo,addrlen);printf("服务器:%s 端口:%d\n",inet_ntoa(serverinfo.sin_addr),ntohs(serverinfo.sin_port));//创建子线程pthread_create(&id,NULL,son_fun,(void *)&socketfd);//读写while(1){char readbuff[512]={0};gets(readbuff);if(strlen(readbuff)==0) continue;write(socketfd,readbuff,sizeof(readbuff));}//关闭close(socketfd);return 0;
}
int Socket(int domain,int type,int protocol)
{int socketFd = socket(domain,type,protocol);if(socketFd == -1){perror("socket");exit(1);}return socketFd;
}
int Connect (int sockfd,struct sockaddr * serv_addr,int addrlen)
{int val = connect(sockfd,serv_addr,addrlen);if(val == -1){perror("connect");exit(1);}return 0;
}
void *son_fun(void * arg)
{int readpipefd = *((int *)arg);char readbuff[512]={0};while(1){if(read(readpipefd,readbuff,sizeof(readbuff))>0){printf("接收:%s\n",readbuff);}else{close(readpipefd);pthread_exit(NULL);}}
}

服务端:多线程服务端,具备基础通信功能

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <semaphore.h>
typedef struct sockaddr  SA;
typedef struct sockaddr_in  SIN;
#define MAXBACKLOG   100int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);
void *son_fun(void * arg);int main(int argc,char *argv[])
{	//建立监听套接字int socketfd = Socket(AF_INET,SOCK_STREAM,0);//需要进行重用地址及其端口号int  opt = 1;setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//绑定信息编写服务器信息SIN   serverinfo;serverinfo.sin_family = AF_INET;serverinfo.sin_port   = htons(atoi(argv[2]));serverinfo.sin_addr.s_addr =  inet_addr(argv[1]);int addrlen = sizeof(SIN);Bind(socketfd,(SA*)&serverinfo,addrlen);//监听Listen(socketfd,MAXBACKLOG);//读写while(1){//等待连接SIN clientinfo;int  clientaddrlen = sizeof(SA);int newfd = Accept(socketfd,(SA*)&clientinfo,&clientaddrlen);printf("客户端地址:%s 端口号:%d\n",inet_ntoa(clientinfo.sin_addr),ntohs(clientinfo.sin_port));//创建子线程pthread_t id;pthread_create(&id,NULL,son_fun,(void *)&newfd);}//关闭close(socketfd);return 0;
}
int Socket(int domain,int type,int protocol)
{int socketFd = socket(domain,type,protocol);if(socketFd ==-1){perror("socket");exit(1);}return socketFd;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{int val = bind(sockfd,my_addr,addrlen);if(val){perror("bind");exit(1);}return 0;
}
int Listen(int s,int backlog)
{int val = listen(s,backlog);if(val == -1){perror("listen");exit(1);}return val;
}
int Accept(int s,struct sockaddr * addr,int * addrlen)
{int NEWfd = accept(s,addr,addrlen);if(NEWfd == -1){perror("listen");exit(1);}return NEWfd;
}
void *son_fun(void * arg)
{int readpipefd = *((int *)arg);char readbuff[512]={0};while(1){if(read(readpipefd,readbuff,sizeof(readbuff))>0){printf("接收:%s\n",readbuff);}else{close(readpipefd);pthread_exit(NULL);}}
}

基于 TCP 服务端/客户端编程详细案例⭐

点我查看

函数

创建套接字  socket

头文件:
  #include<sys/types.h>
  #include<sys/socket.h>
函数原型:: int socket(int domain,int type,int protocol);
参数介绍:
  domain:指定使用何种的地址类型。
    PF_INET/AF_INET Ipv4 网络协议
    PF_INET6/AF_INET6 Ipv6 网络协议
  type:
    SOCK_STREAM 提供双向连续且可信赖的数据流,即 TCP。
    SOCK_DGRAM 使用不连续不可信赖的数据包连接。
  protocol:来指定 socket 所使用的传输协议编号,通常为0.
返回值:成功则返回 socket 文件描述符,失败返回-1。

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

绑定函数  bind

头文件:
  #include<sys/types.h>
  #include<sys/socket.h>
函数原型::int bind(int sockfd,struct sockaddr * my_addr,int addrlen);
参数介绍:
  sockfd:socket 文件描述符。
  my_addr:sockaddr 结构体。
  addrlen:结构体长度。
返回值:功则返回0 ,失败返回-1,错误原因存于 errno 中。

//通用的套接字地址结构
struct sockaddr
{unsigned short int sa_family;char sa_data[14];
};
//IPv4 套接字地址结构
struct sockaddr_in
{unsigned short int sin_family;uint16_t sin_port;struct in_addr sin_addr;unsigned char sin_zero[8];
};
struct in_addr
{uint32_t s_addr;
};
//初始化服务器信息
struct sockaddr_in serverinfo;
serverinfo.sin_family =AF_INET; //协议 IPV4
serverinfo.sin_port =htons(atoi(argv[2])); //网络字节序(大端字节序)与主机字节序(小端字节序) 
serverinfo.sin_addr.s_addr= inet_addr(argv[1]);//192.168.5.166 2159634568 80.B9.68.88 128.185.104.136 点分十进制格式
//计算长度
int addrlen = sizeof(struct sockaddr_in);
//绑定
bind(socketfd,(struct sockaddr*)&serverinfo,addrlen);
大小端排序转换函数

主机字节序:主机内部内存中数据的处理方式。Intel 机器采用小端排序方式
网络字节序:网络字节顺序是 TCP/IP 中规定好的一种数据表示格式,它与具体的 CPU 类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用大端排序方式
这里提供一些端口格式转换函数:(n 代表网络,h代表本地,所以h to n 就是本地转换成网络)
在这里插入图片描述

地址格式转换函数

方便把 xxx.xxx.xxx.xxx 类型的地址与成十进制数字相互转换。
int inet_aton(const char *straddr,struct in_addr *addrptr);
作用:把点分十进制格式 IP 转换成 struct in_addr 类型 IP
char * inet_ntoa(struct in_addr inaddr);
作用:把 struct in_addr 类型的 IP 转换为点分十进制格式
in_addr_t inet_addr(const char *straddr);
作用:把点分十进制 IP 转换为 in_addr_t(uint32)类型 IP
示例:inet_aton(“192.168.1.1”,&ser_addr.sin_addr);

监听  listen

头文件:
  #include<sys/socket.h>
函数原型:int listen(int s,int backlog);
参数介绍:
  s:socket 文件描述符。
  backlog:最大连接数。
返回值: 成功则返回 0,失败返回-1,错误原因存于 errno。

	listen(socketfd,MAXBACKLOG);

等待客户端连接  accept

头文件:
  #include<sys/types.h>
  #include<sys/socket.h>
函数原型:int accept(int s,struct sockaddr * addr,int * addrlen);
参数介绍:
  s:socket 文件描述符。
  addr:远程主机的地址数据结构体。
  addrlen:结构体大小。
返回值:成功则返回客户端的 socket 处理代码,失败返回-1,错误原因存于 errno 中。

	struct sockaddr_in clientinfo;int clientaddrlen =sizeof(SA);int clientfd = accept(socketfd,(struct sockaddr*)&clientinfo,&clientaddrlen);

连接服务器   connect

头文件:
  #include<sys/types.h>
  #include<sys/socket.h>
函数原型:int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
参数介绍:
  sockfd:socket 文件描述符。
  addr:远程主机的地址数据结构体。
  addrlen:结构体大小。
返回值:成功则返回 0,失败返回-1,错误原因存于 errno 中。

	connect(socketfd,(struct sockaddr*)&serverinfo,addrlen);

发送函数  send

头文件:
  #include<sys/types.h>
  #include<sys/socket.h>
函数原型:int send(int s,const void * msg,int len,unsigned int falgs);
参数介绍:
  s:socket 文件描述符。
  msg:发送字符串。
  len:字符串长度。
  falgs:设置flags为0时,send和wirte是同等的。
返回值:

	char sendbuff[128] = "11111";send(socketfd,sendbuff,sizeof(sendbuff),0);

接收函数  recv

头文件:
  #include<sys/types.h>
  #include<sys/socket.h>
函数原型:int recv(int s,void *buf,int len,unsigned int flags);
参数介绍:
  s:socket 文件描述符。
  msg:接收字符串。
  len:接收字符串长度。
  falgs:设置flags为0时,recv和re’a’d是同等的。
返回值:

	char readbuff[128] = {0};send(socketfd,readbuff,sizeof(readbuff),0);

NAT映射

概述

  网络地址转换(NAT)是一种用于访问 Internet 访问模式广域网(WAN)的技术,用于将私有(保留)地址转换为合法 IP 地址。NAT 不仅能够有效地额抵抗外部网络攻击(防火墙:外来连接),还能够在 IP 地址分配不理想,不足的时候有效,合理化的分配 IP 地址,从而能够进行互联网访问。
在这里插入图片描述

NAT 的优缺点

优点:
①极大的节省了合法的 IP 地址。
②能够处理地址重复情况,避免了地址的重新编号,增加了编址的灵活性。
③隐藏了内部网络地址,增强了安全性。
④可以使多个使用 TCP 负载特性的服务器之间实现基本的数据包负载均衡。
缺点:
①由于 NAT 要在边界路由器上进行地址的转换,增大了传输的延迟。
②由于 NAT 改动了 IP 地址,失去了跟踪端到端 IP 流量的能力。当出现恶意流量时,会使故障排除和流量跟踪变的更加棘手。
③不支持一些特定的应用程序。如早期版本的 MSN。
④增大了资源开销。处理 NAT 进程增加了 CPU 的负荷,并需要更多内存来存储 NAT 表项。

内网穿透(打洞)技术

NAT 机制导致:
服务器:私网   对   客户端:私网 需要打洞
服务器:公网   对   客户端:私网 无需打洞
服务器:私网   对   客户端:公网 需要打洞
服务器:公网   对   客户端:公网 无需打洞
了解更多

UDP编程

概念

  UDP(user datagram protocol)的中文叫用户数据报协议,属于传输层(TCP/UDP)。UDP 是面向非连接的协议,它不与对方建立连接,而是直接把我要发的数据报发给对方。所以 UDP 适用于一次传输数据量很少、对可靠性要求不高的或对实时性要求高的应用场景。正因为 UDP 无需建立连接如三次握手,而使得通信效率很高。

通信流程

在这里插入图片描述

基于 UDP 客户端编程思路

1.建立 socket 套接字描述符
2.发送数据到服务器端
3.接收服务器端信息
4.关闭

基于 UDP 服务器端编程思路

1.服务器端开始建立 socket 描述符
2.编写服务器信息
3.sockfd 描述符与服务器进行绑定
4.接收客户端发送过来的数据
5.发送数据到客户端
6.关闭

基于UDP 客户端/服务端编程例子⭐

客户端:具备基础通信功能

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include <pthread.h>
typedef struct sockaddr  SA;
typedef struct sockaddr_in  SIN;
#define MAXBACKLOG   100int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen);
int Sendto ( int s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen );int main(int argc,char *argv[])
{	//建立监听套接字int socketfd = Socket(AF_INET,SOCK_DGRAM,0);//绑定信息编写服务器信息SIN   serverinfo;serverinfo.sin_family =AF_INET;serverinfo.sin_port   =htons(atoi(argv[2]));serverinfo.sin_addr.s_addr=  inet_addr(argv[1]);int addrlen = sizeof(SIN);//读写while(1){char readbuff[512] = {0};int fromlen = sizeof(SIN);gets(readbuff);//回发Sendto (socketfd,readbuff,strlen(readbuff), 0,(SA*)&serverinfo,fromlen);}//关闭close(socketfd);return 0;
}
int Socket(int domain,int type,int protocol)
{int socketFd = socket(domain,type,protocol);if(socketFd ==-1){perror("socket");exit(1);}return socketFd;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{int val = bind(sockfd,my_addr,addrlen);if(val){perror("bind");exit(1);}return 0;
}
int Recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen)
{int val = recvfrom(s,buf,len,flags ,from ,fromlen);if(val == -1){perror("recvfrom");exit(1);}return 0;
}
int Sendto ( int s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen )
{int val = sendto (s ,msg,len,flags,to ,tolen );if(val == -1){perror("sendto");exit(1);}return 0;
}

服务端:具备基础通信功能

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include <pthread.h>typedef struct sockaddr  SA;
typedef struct sockaddr_in  SIN;
#define MAXBACKLOG   100int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen);
int Sendto ( int s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen );int main(int argc,char *argv[])
{	//建立监听套接字int socketfd = Socket(AF_INET,SOCK_DGRAM,0);//绑定信息编写服务器信息SIN   serverinfo;serverinfo.sin_family =AF_INET;serverinfo.sin_port   =htons(atoi(argv[2]));serverinfo.sin_addr.s_addr=  inet_addr(argv[1]);int addrlen = sizeof(SIN);Bind(socketfd,(SA*)&serverinfo,addrlen);//读写while(1){char readbuff[512]={0};SIN from;int fromlen = sizeof(SIN);Recvfrom(socketfd,readbuff,sizeof(readbuff),0 ,(SA*)&from ,&fromlen);printf("ip:%s port:%d Data:%s\n",inet_ntoa(from.sin_addr),ntohs(from.sin_port),readbuff);//回发Sendto (socketfd,readbuff,strlen(readbuff), 0,(SA*)&from,fromlen);}//关闭close(socketfd);return 0;
}
int Socket(int domain,int type,int protocol)
{int socketFd = socket(domain,type,protocol);if(socketFd ==-1){perror("socket");exit(1);}return socketFd;
}int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{int val = bind(sockfd,my_addr,addrlen);if(val){perror("bind");exit(1);}return 0;
}
int Recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen)
{int val = recvfrom(s,buf,len,flags ,from ,fromlen);if(val == -1){perror("recvfrom");exit(1);}return 0;
}
int Sendto ( int s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen )
{int val = sendto (s ,msg,len,flags,to ,tolen );if(val == -1){perror("sendto");exit(1);}return 0;
}

函数

发送函数  sendto

头文件:
  #include<sys/socket.h>
函数原型:int sendto(int s,const void *msg,int len,unsigned int flags,const struct sockaddr * to,int tolen);
参数介绍:
  s:套接字文件描述符。
  msg:指向要发送数据的容器地址。
  len:要发送的数据长度。
  flags:一般为 0 阻塞等待。
  to:目地机的 ip 地址和端口号信息。
  tolen:地址长度。
返回值:成功返回发送的字节数,出错返回-1。

	struct sockaddr_in to;int tolen = sizeof(struct sockaddr_in);char sendbuff[512] = {0};Sendto(socketfd,sendbuff,strlen(sendbuff), 0,(struct sockaddr*)&to,tolen);

接收函数  recvfrom

头文件:
  #include<sys/socket.h>
函数原型:int recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen);
参数介绍:
  s:套接字文件描述符。
  buf:指向要存储数据容器的地址。
  len:要保存的数据长度。
  flags:—般为 0 阻塞等待。
  from:源主机的 ip 地址和端口号信息。
  formlen:地址长度。
返回值:成功返回接收的字节数,出错返回-1。

	struct sockaddr_in from;int fromlen = sizeof(struct sockaddr_in);char readbuff[512] = {0};Recvfrom(socketfd,readbuff,sizeof(readbuff),0,(struct sockaddr*)&from ,&fromlen);

UDP广播

概念

  广播 UDP 与单播 UDP 的区别就是 IP 地址不同,广播使用广播地址 255.255.255.255,将消息发送到在同一广播网络上的每个主机。值得强调的是:本地广播信息是不会被路由器转发。当然这是十分容易理解的,因为如果路由器转发了广播信息,那么势必会引起网络瘫痪。这也是为什么 IP 协议的设计者故意没有定义互联网范围的广播机制。广播地址通常用于在网络游戏中处于同一本地网络的玩家之间交流状态信息等。其实广播顾名思义,就是想局域网内所有的人说话,但是广播还是要指明接收者的端口号的,因为不可能接受者的所有端口都来收听广播。

广播特点

1.数据传输不用建立连接,所以不可靠(符合 udp 协议的特点)。
2.数据的发送是面向整个子网的,任何一台在子网内的计算机都可以接收到相同的数据。
3.广播用于 udp 和原始 IP,不能用于 TCP。

广播地址

1.直接广播地址:
指 Host 部分全为 1 的广播地址。如:192.168.0.255。当某机器发出目的地址为直接广播(如:192.168.199.255)时,路由器通过查找路由表可以转发,直到该网段。
2.受限广播地址:
也称本地广播地址,它不被路由发送,但会被送到相同物理网络段上的所有主机,IP 地址的网络号和主机号全为 1 就是地址 255.255.255.255,当某机器发出目的地址为本地广播时,路由器不会转发该包。所以该包只能限制在本网段。

网络编程服务器模型

回射服务器

  即接收客户端的消息,把消息原封不动的返回去。

迭代服务器

  在多个客户端连接的时候,服务器在同一时刻只能响应一个客户端的请求。

并发服务器

  在多个客户端连接的时候,服务器在同一时刻可以响应多个客户端的请求。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苍穹外卖项目笔记(2)

1 Nginx 反向代理和负载均衡 1.1 概念 【Tips】可以看到前端请求地址和后端接口地址并不匹配&#xff0c;这里涉及到 nginx 反向代理 &#xff0c;就是将前端发送的动态请求由 nginx 转发到后端服务器 使用 nginx 作反向代理的好处&#xff1a; 提高访问速度&#xff08;在请…

Vue3 customRef自定义ref 实现防抖

防抖就是防止在input 框中每输入一个字符就要向服务器请求一次&#xff0c;只要在用户输入完成过一段时间再读取用户输入的内容就能解决这个问题&#xff0c;减小服务器的压力。 1. 自定义ref是一个函数&#xff0c;可以接受参数。 比如我们自定义一个myRef&#xff1a; setu…

二进制位(计算机存储数据最小单位)

二进制数据中的一个位(bit)简写为b&#xff0c;音译为比特&#xff0c;是计算机存储数据的最小单位。一个二进制位只能表示0或1两种状态&#xff0c;要表示更多的信息&#xff0c;就要把多个位组合成一个整体&#xff0c;一般以8位二进制组成一个基本单位。计算机内部数据以二进…

美团面试:微服务如何拆分?原则是什么?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如美团、字节、如阿里、滴滴、极兔、有赞、希音、百度、网易的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 微服务如何拆分&#xff1f; 微服务拆分的规范和原则…

Shell判断:模式匹配:case(二)

简单的JumpServer 1、需求&#xff1a;工作中&#xff0c;我们需要管理N多个服务器。那么访问服务器就是一件繁琐的事情。通过shell编程&#xff0c;编写跳板程序。当我们需要访问服务器时&#xff0c;看一眼服务器列表名&#xff0c;按一下数字&#xff0c;就登录成功了。 2、…

在Vue3中使用Element-Plus分页(Pagination )组件

开发过程中数据展示会经常使用到&#xff0c;同时分页功能也会添加到页面中。 记&#xff1a;在Vue3中使用Element-Plus分页组件与表格数据实现分页交互。 开始实现 引入表格和分页组件的H5标签。 <strong>Element-Plus分页组件使用</strong> <div><el-t…

Windows配置全局代理

一. Windows下为PowerShell/CMD/Git设置代理 —————————————————————————————————————————————————————— 二. [WinError 10061] 由于目标计算机积极拒绝&#xff0c;无法连接。 keyerror:192。 HTTP Error 403: Forbidd…

〖大前端 - 基础入门三大核心之JS篇㊵〗- DOM事件监听及onxxx的使用

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

【机器学习】033_反向传播

一、计算图、反向传播原理 1. 回顾前向传播 例&#xff1a;假设现在有一个神经网络&#xff0c;其仅有一个输出层和一个神经单元 定义 定义 &#xff0c;即激活函数对激活值不再做具体处理 定义平方损失函数 &#xff0c;计算a的值与真实值的差距 此时&#xff0c;通过计算…

【STL】string类 (上) <vector>和<list>的简单使用

目录 一&#xff0c;什么是 STL 二&#xff0c;STL 的六大组件 三&#xff0c;标准库中的 string 类 1&#xff0c;string 类 2&#xff0c;string 类的常用接口 1&#xff0c;string类对象的常见构造 2&#xff0c;string&#xff08;const string& str&#xff…

如何构建更简洁的前端架构?

目录 为什么需要前端架构&#xff1f; 那么&#xff0c;前端架构是什么样的呢&#xff1f; 使用了哪些层&#xff1f; 那么&#xff0c;这种架构会出什么问题呢&#xff1f; 我们应该如何避免这些错误&#xff1f; 哪些原则应适用于组件&#xff1f; Anti-Patterns 反模…

C++实战学习笔记

文章目录 erase()uniquevector的insert()std::string::npos erase() &#xff08;1&#xff09;erase(pos,n); 删除从pos开始的n个字符&#xff0c;比如erase(0,1)就是删除第一个字符 &#xff08;2&#xff09;erase(position);删除position处的一个字符(position是个string类…

无服务器开发实例|微服务向无服务器架构演进的探索

在当今的技术环境中&#xff0c;许多组织已经从构建单一的应用程序转变为采用微服务架构。微服务架构是将服务分解成多个较小的应用程序&#xff0c;这些应用程序可以独立开发、设计和运行。这些被拆分的小的应用程序相互协作和通信&#xff0c;为用户提供全面的服务。在设计和…

vue项目中使用vant轮播图组件(桌面端)

一. 内容简介 vue使用vant轮播图组件(桌面端) 二. 软件环境 2.1 Visual Studio Code 1.75.0 2.2 chrome浏览器 2.3 node v18.14.0 三.主要流程 3.1 安装环境 3.2 添加代码 3.3 结果展示 四.具体步骤 4.1 安装环境 先安装包 # Vue 3 项目&#xff0c;安装最新版 Va…

改进YOLOv8:结合ConvNeXt V2骨干网络!使用MAE共同设计和扩展ConvNet

🗝️YOLOv8实战宝典--星级指南:从入门到精通,您不可错过的技巧   -- 聚焦于YOLO的 最新版本, 对颈部网络改进、添加局部注意力、增加检测头部,实测涨点 💡 深入浅出YOLOv8:我的专业笔记与技术总结   -- YOLOv8轻松上手, 适用技术小白,文章代码齐全,仅需 …

YOLO改进系列之注意力机制(GatherExcite模型介绍)

模型结构 尽管在卷积神经网络&#xff08;CNN&#xff09;中使用自底向上的局部运算符可以很好地匹配自然图像的某些统计信息&#xff0c;但它也可能阻止此类模型捕获上下文的远程特征交互。Hu等人提出了一种简单&#xff0c;轻量级的方法&#xff0c;以在CNN中更好地利用上下…

树与二叉树堆:二叉树

二叉树的概念&#xff1a; 二叉树是树的一种&#xff0c;二叉树是一个节点&#xff0c;最多只有两个子节点&#xff0c;二叉树是一个特殊的树二叉树的度最大为2 从上图可得一棵二叉树是结点的一个有限集合&#xff0c;该集合: 或者为空由一个根结点加上两棵别称为左子树和右子…

环境配置|GitHub——如何在github上搭建自己写的网站

下面简单地总结了从本地的网页文件到在github服务器上展示出来即可以通过网络端打开的过程&#xff1a; &#xff08;以下可能会出现一些难点&#xff0c;照着做就可以了&#xff0c;由于笔者是小白&#xff0c;也不清楚具体原理是什么&#xff0c;希望有一天成为大神的时候能轻…

JVM对象创建与内存分配

对象的创建 对象创建的主要流程&#xff1a; 类加载推荐博客&#xff1a;JVM类加载机制详解 类加载检查 虚拟机遇到一条new指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载、解析…

Java八股文(急速版)

Redis八股文 我看你在做项目的时候都使用到redis&#xff0c;你在最近的项目中哪些场景下使用redis呢? 缓存和分布式锁都有使用到。 问&#xff1a;说说在缓存方面使用 1.在我最写的物流项目中就使用redis作为缓存&#xff0c;当然在业务中还是比较复杂的。 2.在物流信息…