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   100

int 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);
	//connect
	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);
	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   100

int 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   100

int 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   100

int 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,当某机器发出目的地址为本地广播时,路由器不会转发该包。所以该包只能限制在本网段。

网络编程服务器模型

回射服务器

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

迭代服务器

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

并发服务器

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中间件安全:Apache Tomcat 弱口令.(反弹 shell 拿到服务器的最高控制权.)

中间件安全&#xff1a;Apache Tomcat 弱口令. Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。 通过弱口令登录后台&#xff0c;部署 war 包…

【狂神说Java】redis

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;【狂神说Java】 &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#xff0c…

Linux02 VIM编辑器

Linux02 VIM编辑器 基本上 vi/vim 共分为三种模式&#xff0c; 分别是命令模式&#xff08;Command mode&#xff09;&#xff0c;输入模式&#xff08;Insert mode&#xff09;和底线命令模式&#xff08;Last line mode&#xff09;。 三种状态进行切换 插入模式&#xff1a…

如何优雅的避免空指针异常

文章目录 1.数据准备2.实战&#xff1a;获取用户所在的城市2.1.直接获取&#xff1b;容易出现空指针异常。2.2.使用if-else判断&#xff1b;避免了出现空指针的问题&#xff0c;但是代码结构层次嵌套多&#xff0c;不美观2.3.使用工具类美化一下if判断代码2.4.使用Optional解决…

html实现计算器源码

文章目录 1.设计来源1.1 主界面1.2 计算效果界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134532725 html实现计算器源码&#xff0c;计算器源码&#xff0c;简易计…

2022最新版-李宏毅机器学习深度学习课程-P51 BERT的各种变体

之前讲的是如何进行fine-tune&#xff0c;现在讲解如何进行pre-train&#xff0c;如何得到一个pre train好的模型。 CoVe 其实最早的跟预训练有关的模型&#xff0c;应该是CoVe&#xff0c;是一个基于翻译任务的一个模型&#xff0c;其用encoder的模块做预训练。 但是CoVe需要…

CV计算机视觉每日开源代码Paper with code速览-2023.11.17

点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【点云分割】&#xff08;CVPR2023&#xff09;Center Focusing Network for Real-Time LiDAR Panoptic Segmentation 论文地址&#xff1a;…

【每日OJ —— 232.用栈实现队列(栈)】

每日OJ —— 232.用栈实现队列&#xff08;栈&#xff09; 1.题目&#xff1a;232.用栈实现队列&#xff08;栈&#xff09;2.解法2.1.方法讲解2.1.1.算法讲解2.1.2.代码实现2.1.3.提交通过展示 1.题目&#xff1a;232.用栈实现队列&#xff08;栈&#xff09; 2.解法 2.1.方法…

图解算法数据结构-LeetBook-栈和队列04_望远镜中最高的海拔_滑动窗口

科技馆内有一台虚拟观景望远镜&#xff0c;它可以用来观测特定纬度地区的地形情况。该纬度的海拔数据记于数组 heights &#xff0c;其中 heights[i] 表示对应位置的海拔高度。请找出并返回望远镜视野范围 limit 内&#xff0c;可以观测到的最高海拔值。 示例 1&#xff1a; 输…

AI技术实力认证,宏电股份荣获2023年度AI天马“领军企业”

近日&#xff0c;由中国新一代人工智能发展战略研究院指导&#xff0c;深圳市人工智能产业协会主办&#xff0c;广东未来产业研究院承办的2023年度“AI天马”认定最终结果公布&#xff0c;宏电股份荣获AI天马“领军企业”奖项。 宏电股份基于20余年的技术沉淀&#xff0c;在工业…

【OpenGauss 列存储学习总结 2】

OpenGauss 列存储学习总结 2 概述文章链接 概述 列存储是一种优化技术&#xff0c;用于在数据库系统中存储和查询大量数据。与传统的行存储方式不同&#xff0c;列存储将每个列的数据分别存储在独立的存储单元中&#xff0c;而不是按照行的方式存储。这种存储方式在分析性查询、…

Java GUI实现桌球小游戏

桌球游戏是一种室内运动&#xff0c;通常在一个正式的桌球台上进行。这种游戏也被称为台球或母球。桌球游戏的目标是使用一个击球杆将彩球击入桌面四个角落的袋子中&#xff0c;得分最高的一方获胜。桌球游戏需要一定的技巧和策略&#xff0c;因此是一项受欢迎的竞技运动和休闲…

Vue:[##################] / reify:core-js: timing reifyNode:node_modules/lodash Completed in 4923ms

Vue创建项目卡在[##################] / reify:core-js: timing reifyNode:node_modules/lodash Completed in 4923ms不动的问题. 遇到问题不要慌&#xff0c;别人可以你也可以。 1.什么是npm npm是node官方的包管理器。 cnpm是个中国版的npm&#xff0c;是淘宝定制的 cnpm (g…

第2关:图的深度优先遍历

任务要求参考答案评论2 任务描述相关知识编程要求测试说明 任务描述 本关任务&#xff1a;以邻接矩阵存储图&#xff0c;要求编写程序实现图的深度优先遍历。 相关知识 图的深度优先遍历类似于树的先序遍历, 是树的先序遍历的推广&#xff0c;其基本思想如下&#xff1a; …

广西梧州盾构机主轴承尺寸测量检测CAV检测上门三维扫描-CASAIM中科广电

一、背景介绍 大型盾构机在掘进过程中&#xff0c;只能前进&#xff0c;不能倒退&#xff0c;盾构机掘进过程中&#xff0c;主轴承“手持”刀盘旋转切削掌子面并为刀盘提供旋转支撑&#xff0c;主轴承一旦失效&#xff0c;会造成严重损失。因此&#xff0c;主轴承是盾构机刀盘…

软件系统运维方案

1.项目情况 2.服务简述 2.1服务内容 2.2服务方式 2.3服务要求 2.4服务流程 2.5工作流程 2.6业务关系 2.7培训 3.资源提供 3.1项目组成员 3.2服务保障 点击获取所有软件开发资料&#xff1a;点我获取

PHP中cookie与session使用指南

PHP中cookie与session使用指南 Cookie和session的出现&#xff0c;是为了解决http协议无状态交互的窘境&#xff0c;它们都用于存储客户端的相关信息 0x01 Cookie使用 简介 Cookie 是一种在客户端存储数据的机制&#xff0c;通常用于记录用户的状态和偏好。下面将介绍如何在…

软件测试最重要的事:测试用例的编写

前言 软件测试用例得出软件测试用例的内容&#xff0c;其次&#xff0c;按照软件测试写作方法&#xff0c;落实到文档中&#xff0c;两者是形式和内容的关系&#xff0c;好的测试用例不仅方便自己和别人查看&#xff0c;而且能帮助设计的时候考虑的更周。 一个好的测试用例必…

企业app软件定制开发的重点是什么?|小程序网站搭建

企业app软件定制开发的重点是什么&#xff1f;|小程序网站搭建 在当今数字化时代&#xff0c;企业对于信息技术的依赖越来越大。为了适应市场需求并提高内部运营效率&#xff0c;许多企业开始寻求定制开发企业app软件。这种定制开发可以根据企业的具体需求和业务流程进行个性化…

DITTEL控制器维修SENSITRON6-2AE

DITTEL工控产品维修包括&#xff1a;德国DITTEL平衡测试仪维修,DITTEL模块&#xff0c;过程监控模块&#xff0c;DITTEL控制器&#xff0c;平衡头&#xff0c;机电平衡头&#xff0c;显示器&#xff0c;平衡系统等产品。 DITTEL过程控制模块维修 DM6000是一个过程控制模块&…