UDP编程

通常使用“点分十进制”字符串表示IP地址,用3个“.”划分成四个区。每个区的表示范围为0~255

端口号具有2个字节16个比特位的整数

IP是将数据从A主机交付给B主机

端口号用来标识一个进程,一个端口号只能被一个进程占用

IP地址+端口号=套接字,可以进行数据层面的来往,本质上就是进程间的通信

端口号和进程ID的区别:

每一个进程都需要有PID,但不是所有进程都有端口号,除非这个进程投身于网络服务

一个进程可以绑定多个端口号,但是一个端口号不能绑定多个进程

简单对比TCP与UDP:

认识TCP(传输控制协议)协议保证可靠性

超时重传、面向连接、拥塞控制、按需到达、去重

传输层协议

有连接

可靠

面向字节流

认识UDP(用户数据报协议)协议:不保证可靠性

传输层协议

无连接

不可靠

面向数据报

网络字节序列-------------->大端序列,由底层自动帮我们完成

小端:数据的低位放在低地址处

大端:数据的高位放在低地址处

网络数据流的地址规定:先发出的数据是低地址,后发出去的数据是高地址

调用库函数做网络字节序列和主机字节序的转换:

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntonhl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

h表示host,n表示network

编写UDP

创建socket文件描述符(TCP/UDP,客户端+服务器)

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

domain:套接字类型

                AF_UNIX :域间套接字,用来进行本地通信

                AF_INET :使用Ipv4

                AF_INET6:使用ipv6

type:表示服务类型

           SOCK_DGRAM:无连接不可靠指定大小长度的服务

int protocol:协议类型,因为以上的设定明确表示使用的udp,所以这里不用再设定,直接写0

返回值:成功返回文件描述符(以某种方式打开网卡),失败返回-1

网卡是一个文件,这样就可以被进程操作,进程将操作的文件放入自身的文件描述符表中,通过文件描述符来访问文件描述符表中的不同文件,往文件描述符上读写就是往网卡中读写

所谓文件描述符本质上是PCB中文件描述符表中的下标,以便找到这个文件进行操作

绑定端口号

int bind(int socket,const struct sockaddr *address,socklen_t address_len);

socket:文件描述符

address:绑定的端口号

成功返回0,失败返回-1

开始监听socket

int listen(int socket,int backlog);

接收请求

int accept(int socket,struct sockaddr*address,socklen_t*address_len);

建立连接

int connet(int sockfd,const struct sockadd*addr,socklen_t addrlen);

sockaddr这一类套接字接口可以接收任意类型,类似于void*,但出现在void*之前,可以根据地址类型来具体划分接口类型

我们可以通过netstat -nlup 查看udp服务器

具体实现代码:

服务器端:

 1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/socket.h>
  4 #include<netinet/in.h>
  5 #include<arpa/inet.h>
  6 
  7 int main(int argc,char* argv[])
  8 {
  9     if(argc!=3)
 10     {
 11         printf("Usage:%s [ip] [port]",argv[0]);
 12         return 1;
 13     }
 14     int sock=socket(AF_INET,SOCK_DGRAM,0);
 15     if(sock==-1)
 16     {
 17         perror("socket");
 18         return -1;                                                                                                                                       
 19     }
 20     struct sockaddr_in local;
 21     local.sin_family=AF_INET;//表示底层使用的协议是ipv4
 22     local.sin_port=htons(atoi(argv[2]));//使用的端口号,网络中传播的端口号为整形,
 23                                         //这里需要用atoi进行转化,此外要把客户端传递出去还需要将端口号转化为网络字节序列
 24     local.sin_addr.s_addr=inet_addr(argv[1]);//使用的ip地址,此时的ip是类似与”192.168.43.243”这样的点分十进制,需要转化成四字节
 25     if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)//绑定本地的端口号local
 26     {
 27         perror("bind");
 28         return -1;
 29     }
 30     while(1)//不断的对外提供服务
 31     {
 32         struct sockaddr_in client;
 33         socklen_t len=sizeof(client);
 34         char buf[1024];
 35         ssize_t s=recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&client,&len);//用sockaddr_in输出型参数来获取客户端的套接字
 36         if(s>0)
 37         {
 38             buf[s]=0;
 39             
        printf([%s:%d]:%s",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);//将从客户端获取的网络字节序列转换程本地,将网络的四字节转化程本地
    的点分十进制
 40   sendto(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&client,sizeof(client));//接收数据
 41         }
 42     }
 43     return 0;
 44 }                  

客户端:

1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/socket.h>
  5 #include<netinet/in.h>                                                                                                                                   
  6 #include<arpa/inet.h>
  7 #include<stdlib.h>
  8 #include<string.h>
  9 //三个命令行参数 可执行文件 服务器ip 服务器端口号
 10 int main(int argc,char*argv[])
 11 {
 12     if(argc!=3)
 13     {
 14         printf("Usage:%s [ip] [port]",argv[0]);
 15         return 1;
 16     }
 17     int sock=socket(AF_INET,SOCK_DGRAM,0);
 18     if(sock==-1)
 19     {
 20         perror("socket");
 21         return -1;
 22     }
 23     //客户端可以绑定,但是不需要绑定,服务器段必须绑定,因为i服务器必须是众所周知切不可变的
 24     while(1)
 25     {
 26         struct sockaddr_in server;//设置发送方
 27         server.sin_family=AF_INET;//设置协议家族
 28         server.sin_port=htons(atoi(argv[2]));
 29         server.sin_addr.s_addr=inet_addr(argv[1]);//将点分十进制的ip地址转程四字节风格的网络ip地址
 30         char buf[1024];
 31         printf("Please Enter:");
 32         ssize_t s=read(0,buf,sizeof(buf)-1);
 33         if(s>0)
 34         {
 35             buf[s]=0;//为字符串的末尾增加\0
 36             sendto(sock,buf,strlen(buf),0,(struct sockaddr*)&server,sizeof(server));
 37             recvfrom(sock,buf,sizeof(buf)-1,0,NULL,NULL);//设为NULL表示不关心服务器
 38             printf("server echo: %s\n",buf);
 39         }
 40 
 41     }
 42     return 0;
 43 }              

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值