千锋教育+计算机四级网络-计算机网络学习-04

news/2024/11/28 2:50:01/

UDP概述

UDP协议

    面向无连接的用户数据报协议,在传输数据前不需要先建立连接;目地主机的运输层收到UDP报文后,不需要给出任何确认

UDP特点

  1. 相比TCP速度稍快些
  2. 简单的请求/应答应用程序可以使用UDP
  3. 对于海量数据传输不应该使用UDP
  4. 广播和多播应用必须使用UDP

UDP应用

DNS(域名解析)、NFS(网络文件系统)、RTP(流媒体)等

网络编程接口socket

网络通信要解决的是不同主机进程间的通信

  1. 不同主机识别,哪一个主机发,哪一个主机收
  2. 以及多重协议的识别问题,是UDP还是TCP
  3. 首要问题是网络间进程标识问题,因为一个主机存在很多进程,你需要准确的把数据给目的进程(使用端口表示一个进程),哪一个端口发,哪一个端口收

总结就是:IP、端口、协议

20世纪80年代初,加州大学Berkeley分校在BSD(一个UNIX OS版本)系统内实现了TCP/IP协议;其网络程序编程开发接口为socket

随着UNIX以及类UNIX操作系统的广泛应用, socket成为最流行的网络程序开发接口

socket作用

提供不同主机上的进程之间的通信

socket特点

  1. socket也称“套接字”
  2. 是一种文件描述符(特殊的文件描述符),代表了一个通信管道的一个端点(因此socket其实创建的就是一个虚拟的管道-全双工,可以这么简单的理解)
  3. 类似对文件的操作一样,可以使用read、write、close等函数对socket套接字进行网络数据的收取和发送等操作
  4. 得到socket套接字(描述符)的方法调用socket()

UDP编程C/S架构 

这个架构决定我们写代码的流程

UDP编程-创建套接字 

创建socket套接字

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

功能:

创建一个用于网络通信的socket套接字(描述符)

参数:

family:协议族(AF_INET、AF_INET6、PF_PACKET等)

type:套接字类(SOCK_STREAM、SOCK_DGRAM、SOCK_RAW等)

protocol:协议类别(0、IPPROTO_TCP、IPPROTO_UDP等

protocol写0(自动寻找),让它以type为主,确定协议SOCK_STREAM--TCP

SOCK_DGRAM--UDP

返回值:

套接字

特点:

创建套接字时,系统不会分配端口

创建的套接字默认属性是主动的,即主动发起服务的请求;当作为服务器时,往往需要修改为被动的

头文件:

#include <sys/socket.h>

创建UDP套接字demo
int sockfd = 0;
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0)
{perror("socket");close(sockfd);exit(-1);
}注意:
AF_INET:IPv4协议
SOCK_DGRAM:数据报套接字
0:选择所给定的family和type组合的系统默认值

 IPv4套接字地址结构

struct sockaddr_in{sa_family_t sin_family;//2字节   -- 协议族in_port_t sin_port;//2字节          --端口struct in_addr sin_addr;//4字节  --发送方地址或接收方地址char sin_zero[8]//8字节 ---为0,起补位作用,因为要求结构体16个字节,因此定义了8字节的补位};struct in_addr  //该结构体只有一个成员,属于历史遗留问题,之前是有其他成员的{in_addr_t s_addr;//4字节}

在赋值结构体的时候,由于 sin_zero的值需要赋值0,那么我们可以一开始就把结构体清零,然后只赋值协议、端口、IP地址即可

当主机是IPV4或者IPV6发送数据的时候,由于IP地址不同,导致函数使用的不同,因此为了让函数的实用性更强,那么我就把IPV4和IPV6当成整体,因此就把结构体转换为相同的类型即可

为了使不同格式地址能被传入套接字函数,地址须要强制转换成通用套接字地址结构

头文件:#include <netinet/in.h>

struct sockaddr

{

      sa_family_t sa_family;    // 2字节

      char sa_data[14]     //14字节

};

 为了类型转换,就像一个函数能处理char*、int*,那么这个函数就需要成为void*,数据转换,其实我们自己设计一个通用函数的时候也需要注意,如果类型不同,那么我们需要存在一个通用的类型,像void*,能被任何一个数据类型赋值,因此同理,这里也产生了一个类似于void*的类型(为了数据转换,以便处理更多的数据类型)

两种地址结构使用场合

在定义源地址和目的地址结构的时候,选用struct sockaddr_in;

例:

struct  sockaddr_in  my_addr;

这个特点记住就好,等写代码的时候注意一下 

当调用编程接口函数,且该函数需要传入地址结构时需要用struct sockaddr进行强制转换

例:

bind(sockfd,(struct sockaddr*)&my_addr,sizeof(my_addr));

发送数据—sendto函数

ssize_t sendto(int sockfd,const void *buf,

                 size_t nbytes,int flags,

                 const struct sockaddr *to,       

                 socklen_t addrlen);

功能:

向to结构体指针中指定的ip,发送UDP数据

参数:

sockfd:套接字

buf:       发送数据缓冲区

nbytes: 发送数据缓冲区的大小

flags:一般为0

to: 指向目的主机地址结构体的指针

addrlen:to所指向内容的长度

注意:

通过to和addrlen确定目的地址

可以发送0长度的UDP数据包

返回值:

成功:实际发送数据的字符数

失败: -1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int main(int argc,char *argv[])
{//定义好端口和IP地址,并且IP地址是字符串形式,其实这里可以不用初始化unsigned short server_port= 808;  //可以赋值0char *server_ip = "192.168.52.1"; //可以赋值NULL//传递参数需要符合规定,否则错误,并且退出if(argc < 3 ){printf("error\n");exit(1);}//把从终端传进去的IP地址和端口号进行赋值server_ip = argv[1];//通过main函数传参,传入端口号server_port= atoi(argv[2]);    //由于终端输入的是字符串,而端口号是整型,因此使用atoi函数把数字字符串转换为数字/*创建UDP套接字*/int sockfd;sockfd = socket(AF_INET,SOCK_DGRAM,0);  //IPV4和UDPif(sockfd < 0){perror("socket");exit(-1);}/*填充目的server socket地址*/struct sockaddr_in dest_addr;bzero(&dest_addr,sizeof(dest_addr));  //先清零dest_addr.sin_family = AF_INET;//目的套接字地址的协议家族赋值dest_addr.sin_port = htons(server_port);//目的套接字地址的端口号赋值,并且转成网络字节序inet_pton(AF_INET,server_ip,&dest_addr.sin_addr);//目的套接字地址的ip地址赋值printf("send data to UDP server %s:%d!\n",server_ip,port);/*发送数据到目的server*/while(1){char send_buf[512];fgets(send_buf,sizeof(send_buf),stdin);  //使用fgets从终端中输入字符串send_buf[strlen(send_buf)-1] = '\0';//字符串最后一个'\n'变成'\0' //这个很容易忘记,在末尾添加结束字符sendto(sockfd,send_buf,strlen(send_buf),0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));}close(sockfd);  //记得使用完成后,关闭套接字return 0;
}

绑定 bind函数

UDP网络程序想要收取数据需什么条件?

确定的ip地址

确定的port

怎样完成上面的条件呢?

接收端 使用bind函数,来完成地址结构与socket套接字的绑定,这样ip、port就固定了

发送端 在sendto函数中指定接收端的ip、port,就可以发送数据了

因此bind既可以使用在发送端,也可以使用在接收端(客户端和服务端都可以使用bind,都是一般服务端使用bind)

int bind(int sockfd,

        const struct sockaddr *myaddr,socklen_t addrlen);

功能:

将本地协议地址与sockfd绑定

参数:

sockfd: socket套接字

myaddr: 指向特定协议的地址结构指针

addrlen:该地址结构的长度

返回值:

成功:返回0

失败:其他

    struct sockaddr_in Mysource_addr;bzero(&Mysource_addr,sizeof(Mysource_addr));Mysource_addr.sin_family = AF_INET;//目的套接字地址的协议家族赋值Mysource_addr.sin_port = htons(8000);//目的套接字地址的端口号赋值Mysource_addr.sin_addr.s_addr = htonl(INADDR_ANY);INADDR_ANY是通配地址,值为0

接收数据—recvfrom 函数

ssize_t recvfrom(int sockfd, void *buf,

size_t nbytes,int flags,

               struct sockaddr *from,

               socklen_t *addrlen);

功能:

接收UDP数据,并将源地址信息保存在from指向的结构中

并且recvfrom默认是带阻塞的,他需要等信息

参数:

sockfd: 套接字

buf:接收数据缓冲区

nbytes:接收数据缓冲区的大小

flags: 套接字标志(常为0)

from:  源地址结构体指针,用来保存数据的来源

addrlen: from所指内容的长度

注意:

通过from和addrlen参数存放数据来源信息

from和addrlen可以为NULL, 表示不保存数据来源

返回值:

成功:接收到的字符数

失败: -1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int main(int argc,char *argv[])
{struct sockaddr_in Mysource_addr;bzero(&Mysource_addr,sizeof(Mysource_addr));Mysource_addr.sin_family = AF_INET;//目的套接字地址的协议家族赋值Mysource_addr.sin_port = htons(8000);//目的套接字地址的端口号赋值Mysource_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*创建UDP套接字*/int sockfd;sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){perror("socket");exit(-1);}if(bind(sockfd,(struct sockaddr *)&Mysource_addr,sizeof(Mysource_addr)) != 0 ){perror("bind is error");exit(1);}char recvBuff[512];while(1){while( recvfrom(sockfd,recvBuff,512,0,NULL,NULL) == 0 );printf("%s\n",recvBuff);}
}

 

 模拟QQ情况

QQ既可以发信息也可以收消息,说明存在多进程或者多线程情况,一个进程或者线程收消息,而另外一个发消息

 独立完成改代码


http://www.ppmy.cn/news/26047.html

相关文章

【蓝桥日记⑤】2014第五届省赛(软件类)JavaA组❆答案解析

【蓝桥日记⑤】2014第五届省赛&#xff08;软件类&#xff09;JavaA组☃答案解析 文章目录【蓝桥日记⑤】2014第五届省赛&#xff08;软件类&#xff09;JavaA组☃答案解析1、猜年龄2、李白打酒3、神奇算式4、写日志5、锦标赛6、六角填数7、绳圈8、兰顿蚂蚁9、斐波那契10、波动…

Windows系统扩充C盘空间系列方法总结

目录前言方法一 使用自带的Windows的DiskPart扩充C盘1. 打开cmd2.三步命令方法二&#xff1a;使用Windows系统内置磁盘管理扩展C盘方法三. 使用专业磁盘分区工具总结前言 本教程是总结Windows系统进行C盘&#xff08;系统盘&#xff09;扩充空间的系列方法&#xff0c;一般来讲…

用Three.js搭建的一个艺术场景

本文翻译自于Medium&#xff0c;原作者用 Three.js 创建了一个“Synthwave 场景”&#xff0c;效果还不错&#xff0c;在此加上自己的理解&#xff0c;记录一下。在线Demo. 地形构建 作者想要搭建一个中间平坦、两侧有凹凸山脉效果并且能够一直绵延不断的地形&#xff0c;接下…

过滤器和监听器

1、过滤器Filter 作用是防止SQL注入、参数过滤、防止页面攻击、空参数矫正、Token校验、Session验证、点击率统计等等&#xff1b; 使用Filter的步骤 新建类&#xff0c;实现Filter抽象类&#xff1b;重写init、doFilter、destroy方法&#xff1b;在SpringBoot入口中添加注解…

数字经济活动题

讨论活动1-1&#xff1a;数字化 经济数字化&#xff08;数据数字化&#xff0c;高速通信&#xff0c;大容量存储&#xff09;将如何影响您所居住的国家&#xff1f;在网上搜索新闻文章&#xff08;两三篇就够了&#xff09;&#xff0c;并讨论数字化如何影响经济、公共部…

英语基础-状语

1. 课前引语 1. 形容词使用场景 (1). 放在系动词后面作表语 The boy is handsome. (2). 放在名词前面做定语 I like this beautiful girl. (3). 放在宾语后面做补语 You make your father happy. 总结&#xff1a;形容词无论做什么&#xff0c;都离不开名词&#xff0c…

我问chatGPT,在JavaScript中构造函数和类的区别

问&#xff1a;构造器函数和面向中的类是同样的东西吗|&#xff1f; 答&#xff1a;构造器函数和面向对象中的类并不是同样的东西&#xff0c;它们之间有些许不同。 在面向对象编程中&#xff0c;类是一种抽象的概念&#xff0c;它描述了一类具有相同属性和行为的对象。类可以…

浅析SAS协议(1):基本介绍

文章目录概述SAS协议发展历程SAS技术特性SAS设备拓扑SAS phySAS地址SAS设备类型SAS协议分层参考链接概述 SAS&#xff0c;全称Serial Attached SCSI&#xff0c;即串行连结SCSI&#xff0c;是一种采用了串行总线的高速互连技术。通过物理上使用串行总线连结&#xff0c;在链路…