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 通信实战

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

服务端

c 复制代码
#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;
}

客户端

c 复制代码
#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;
}
相关推荐
无足鸟ICT1 小时前
【RHCA+】ipcrm命令(删除IPC资源)
linux
星恒随风2 小时前
MySQL 从零入门(四):表的增删改查与基础查询详解
linux·服务器·数据库·笔记·mysql
张小姐的猫3 小时前
【基于 WebSocket 的多用户网页五子棋】—— 项目结构设计与实用工具类模块
网络·websocket·网络协议
陈希1235 小时前
Linux 网络诊断工具实战:ping、curl、tcpdump、mtr、dig 用法详解
linux·网络·tcpdump
进击的荆棘5 小时前
Linux系统——线程同步与互斥之线程池和安全
linux·运维·服务器·安全·单例模式·线程
刘大望6 小时前
不用买开发板:用 QEMU 走通嵌入式 Linux 全流程(三)存储与网络实地验证
linux·qemu·嵌入式linux·alpine
那明眸似水7 小时前
云原生项目三:Docker秒级启动NextCloud个人网盘存储办公系统
linux·运维·docker·云原生·容器
wuyk5559 小时前
Spider-第03讲-HTTP速通与读懂响应
网络·爬虫·网络协议·http
默|笙18 小时前
【Linux网络】网络层协议 IP(1)理解报头、网段划分
linux·网络·tcp/ip