梦到啥说啥头像

Linux网络编程:UDP网络协议

网络编程

osi 模型(共分为8层)

应用层:为网络用户提供各种服务,例如电子邮件、文件传输等。
表示层:为不同主机间的通信提供统一的数据表示形式。
会话层:负责信息传输的组织和协调,管理进程会话过程。
传输层:管理网络通信两端的数据传输,提供可靠或不可靠的传输服务。
网络层:负责数据传输的路由选择和网际互连。
数据链路层:负责物理相邻(通过网络介质相连)的主机间的数据传输,主要作用包括物理地址寻址、数据帧封装、差错控制等。该层可分为逻辑链路控制子层(LLC)和介质访问控制子层(MAC)。
物理层,负责把主机中的数据转换成电信号,再通过网络介质(双绞线、光纤、无线信道等)来传输,该层描述了通信设备的机械、电气、功能

1.osi模型是描述所有网络的模型, 互联网模型是网络模型中的一种
2.tcp/ip 描述互联网模型。tcp/ip 把osi模型进行了合并

tcp/ip协议栈
1.应用层 ====》应用程序
2.传输层 ====》端口号tcp udp
3.网络层 ====》IP 地址
4.接口层 ====》网卡 驱动 1GB

dns 域名解 把网址翻译成ip地址
DHCP 动态主机配置协议

应用层: HTTP (超文本传输 网页)TFTP FTP(文件传输) SNMP(简单网络管理) DNS
传输层: TCP(传输控制协议,传输文件) UDP(用户数据报协议,实时,音频,视频)
网络层: IP(互联网协议,根据ip查找主机) ICMP(ping,互联网控制管理协议) RIP OSPF(和路由协
议) IGMP(组播管理协议)
接口层 : ARP(ip—>mac 地址解析) RARP

ip的组成

IP地址 == 网络位 + 主机位

ip地址版本, IPV4,和IPV6

网络配置相关
sudo vim /etc/network/interfaces 虚拟机网络配置文件 ,设置ip(手动分配,或自动分配)。ip地址,
永久生效。

网络配置修改后
1.sudo /etc/init.d/networking restart 进行网络设置的加载
2.ifconfig 查看网络相关配置。 主要查看本机的ip
3.ifconfig ens33 192.168.0.13/24 up 临时设置本机ip地址,重启后失效。
4.测试:ping www.baidu.com 测试本机是否可以正常上网
5.netstat -anp 查本本机上所有的网络通信 有那些

词语解释
1.socket 套接字 ,打开本地网络设备后,获得的文件描述符。方便后续进行网络收发。
2.ip+port 地址+端口===》地址用来识别主机, 端口用来识别应用程序
3.端口号的范围: 1-65535
4.网络字节序 ===》大端存储 网络设备使用的字节序
5.主机字节序—》 小端存储 intel, amd ,arm 目前主流CPU都是小端

2. UDP 协议概述

UDP(User Datagram Protocol,用户数据报协议)是传输层的一种无连接协议,定义在 RFC 768 中,全文只有三页,是 TCP/IP 协议族中最简单的协议之一。

它的核心设计哲学是:只做最少的事,UDP 只负责把应用层交下来的数据封装成数据报,加上端口号后交给网络层发送,不保证送达、不保证顺序、不保证不重复,也不做流量控制和拥塞控制。

所以需要注意

udp是用户数据报协议
数据报
1.数据与数据之间有边界
2.发送和接收的次数要对应
3.没有写阻塞。发送太快,会导致数据丢失。
4.读阻塞

UDP 无连接,一个服务端 socket 可以接收很多客户端的包,不维护客户端列表、不保存客户端信息,客户端断开之后,服务端如果还往这个地址发包,数据包会丢失

函数的使用与编程的顺序

server:socket() =>bind()=>recvfrom()===>close()
client:socket()—sendto() -----clos

int socket(int domain, int type, int protocol);

功能:程序向内核提出创建一个基于内存的套接字描述符
参数:domain 地址族,PF_INET =》 AF_INET =>互联网程序
PF_UNIX == AF_UNIX =>单机程序
type 套接字类型:
SOCK_STREAM 流式套接字 =》TCP
SOCK_DGRAM 用户数据报套接字=》UDP
SOCK_RAW 原始套接字 ===》IP
protocol 协议 ==》0 表示自动适应应用层协议。
返回值:成功 返回申请的套接字id
失败 -1;

在这里插入图片描述

int bind(int sockfd, struct sockaddr *my_addr,socklen_t addrlen);

功能:如果该函数在服务器端调用,则表示将参数1相关
的文件描述符文件与参数2 指定的接口地址关联,
用于从该接口接受数据。
sockfd, 需要被绑定 ip 和端口号的套接字
my_addr ipv4 对应的地址结构体,man 7 ip
struct _sockaddr_in ///网络地址结构
{
u_short sin_family; ////地址族
u_short sin_port; ///地址端口
struct in_addr sin_addr; ///地址IP
};
socklen_t addrlen: 参数2 的长度。
返回值:成功 0
失败 -1;

在这里插入图片描述
注意服客户端不需要bind,可有可无,但是服务端必须要有,bind绑定自身,只需要等待客户端来找即可,所以客户端不需要

发送接收函数:

ssize_t sendto(int sockfd, const void buf, size_t len, int flagsconst struct sockaddr *dest_addr, socklen_t addrlen)

功能:用于UDP协议中向对方发送数据。
参数:sockfd 本地的套接字id
buff 本地的数据存储,一般是要发送的数据。
len 要发送的数据长度
flags 要发送数据方式,0 表示阻塞发送。
dest_addr: 必选,表示要发送到的目标主机信息结构体。
addrlen :目标地址长度。
返回值:成功 发送的数据长度
失败 -1;

在这里插入图片描述

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

功能:用于UDP协议中获取对方发送的数据。
参数:sockfd 本地的套接字id
buff 要存储数据的内存区,一般是数组或者动态内存。
len 要获取的数据长度,一般是buff的大小。
flags 获取方式,0 阻塞
src_addr 可选,表示对方的地址信息结构体,
如果为NULL,表示不关心对方地址。
addrlen 对方地址信息结构体大小。
如果对方地址是NULL,则该值也为NULL。
返回值:成功接收到的数据长度
失败 -1;

在这里插入图片描述

7. 代码示例:UDP 通信实战

客户端与服务端使用多线程实现自由交流(单客户端)

服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h>

typedef struct sockaddr *(SA);
int sockfd;
struct sockaddr_in server, cilent;
socklen_t len = sizeof(cilent);
char a[] = "quit";
void *recvv(void *arg)
{
  printf("服务端成功启动\n");
  char buf[1024] = {"0"};

  while (1)
  {
    int ret = recvfrom(sockfd, buf, sizeof(buf), 0, (SA)&cilent, &len);
    if (strcmp(a, buf) == 0)
    {
      printf("客户端已关闭\n");
      exit(0);
    }
    printf("client:%s\n", buf);

    bzero(buf, sizeof(buf));
  }
}
void *sendd(void *arg)
{
  char buff[1024] = {"0"};
  while (1)
  {
    scanf("%s", buff);
    sendto(sockfd, buff, strlen(buff), 0, (SA)&cilent, len);
    if (strcmp(a, buff) == 0)
    {
      printf("服务端已关闭\n");
      exit(0);
    }
    bzero(buff, sizeof(buff));
  }
}
int main(int argc, char **argv)
{
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sockfd < 0)
  {
    perror("socket");
    return -1;
  }

  bzero(&server, sizeof(server));
  bzero(&cilent, sizeof(cilent));

  server.sin_family = AF_INET;
  server.sin_port = htons(50000);
  server.sin_addr.s_addr = inet_addr("192.168.1.233");

  int ret = bind(sockfd, (SA)&server, sizeof(server));
  if (-1 == ret)
  {
    perror("bind");
    return -1;
  }

  pthread_t tid1, tid2;
  pthread_create(&tid1, NULL, recvv, NULL);
  pthread_create(&tid2, NULL, sendd, NULL);

  pthread_join(tid1, NULL);
  pthread_join(tid2, NULL);
  close(sockfd);
  return 0;
}

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h>

typedef struct sockaddr *(SA);
int sockfd;
struct sockaddr_in server, cilent;
 char a[] = "quit";
socklen_t len = sizeof(cilent);
void *crecvv(void *arg)
{
  printf("客户端成功启动\n");
  char buf[1024];
  int quit;
  while (1)
  {
    int ret = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
    if (strcmp(a,buf)==0)
    {
      printf("服务端关闭\n");
      exit(0);
    }
    printf("client:%s\n", buf);
    bzero(buf, sizeof(buf));
  }
}
void *csendd(void *arg)
{
  char buff[1024];
 
  while (1)
  {
    scanf("%s", buff);
    sendto(sockfd, buff, strlen(buff), 0, (SA)&server, sizeof(server));
    if (strcmp(a,buff)==0)
    {
      printf("客户端关闭\n");
      exit(0);
    }
    bzero(buff, sizeof(buff));
  }
}
int main(int argc, char **argv)
{
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sockfd < 0)
  {
    perror("socket");
    return -1;
  }

  bzero(&server, sizeof(server));
  bzero(&cilent, sizeof(cilent));

  server.sin_family = AF_INET;
  server.sin_port = htons(50000);
  server.sin_addr.s_addr = inet_addr("192.168.1.233");

  pthread_t tid1, tid2;
  pthread_create(&tid1, NULL, crecvv, NULL);
  pthread_create(&tid2, NULL, csendd, NULL);

  pthread_join(tid1, NULL);
  pthread_join(tid2, NULL);
  close(sockfd);
  return 0;
}

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qianrushixinshou/article/details/170122430

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--