识字粗堪供赋役,不须辛苦慕公卿。这篇文章主要讲述Linux(程序设计):42---UDP网络编程(单播)相关的知识,希望能为你提供帮助。
一、socket()函数
文章图片
文章图片
服务端通信步骤如下:客户端通信步骤如下:
- ?socket?(); //建立一个socket
- ?bind?(); //将这个socket绑定在某个端口上
- ?sendto?(); //向客户端的某个端口发起请求
- ?recvfrom?(); //如果没有客户端发起请求,则会阻塞在这个函数里
- ?close?(); //通信完成后关闭socket
- ?socket?(); //建立一个socket
- ?sendto?(); //向服务器的某个端口发起请求
- ?recvfrom?(); //如果没有服务端发起请求,则会阻塞在这个函数里
- ?close?(); //通信完成后关闭socket
- ?#include< sys/types.h> ?
- ?#include<
sys/socket.h>
?
int socket(int protofamily, int type, int protocol);
二、bind()函数
?域参数指定通信域;这将选择用于通信的协议系列。这些族在< sys/socket.h> 中定义?
- ? 参数1:即协议域,又称为协议族(family)?
?AF_INET用ipv4地址(32位的)与端口号(16位的)的组合AF_INET6IPV6的?
?AF_LOCAL/或者AF_UNIX(Unix域socket)?
?用一个绝对路径名作为地址。本地通信AF_ROUTE? ?AF_IPXIPX-Novell协议AF_PACKET低层包接口包AF_NETLINK内核用户界面设备?
? 参数2:指定socket类型,与第三个参数有关?
套接字具有指定的类型,该类型指定通信语义
并不是所有的协议族都实现了这些协议类型,例如,AF_INET协议族就没有实现SOCK_SEQPACKET协议类型。
?SOCK_STREAM字节流套接字。?提供序列化的、可靠的、双向连接的字节流。支持带外数据传输(TCP使用)?SOCK_DGRAM数据报套接字。(UDP使用)支持数据报(固定最大长度的无连接、不可靠的消息)SOCK_RAW原始套接字。?RAW类型,提供原始网络协议访问?SOCK_RDM?提供了一个不保证排序的可靠数据报层。不过可能数据会有乱序?SOCK_PACKET专用类型。?不能在通用程序中使用,它直接从设备驱动接受数据?SOCK_SEQPACKET有序分组套接字。?序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出
参数2的socket类型都有一个默认的协议,如果想使用默认的协议,参数3填0即可
- ? 参数3:指定协议类型?
?IPPROTO_TCP?TCP传输协议(SOCK_STRAM默认使用)?IPPTOTO_UDP?UDP传输协议(SOCK_DGRAM默认使用)?IPPROTO_SCTP?STCP传输协议?IPPROTO_TIPC?TIPC传输协议
?返回值:?
- ?socket创建成功:?返回一个socket描述符(sockfd),这个描述字不是固定的,为int类型
- ?socket创建失败:?返回-1,并设置errno变量的值
?errno变量?
?EACCES?没有权限建立制定的protofamily的type的socket?EAFNOSUPPORT?不支持所给的地址类型?EINVAL?不支持此协议或者协议不可用?EMFILE?进程文件表溢出?ENFILE?已经达到系统允许打开的文件数量,打开文件过多?ENOBUFS/ENOMEM?内存不足。socket只有到资源足够或者有进程释放内存?EPROTONOSUPPORT?制定的协议type在domain中不存在
- 若socket创建失败,就会设置errno为相应的值,用户可以检测errno判断出现什么错误
?什么是socket描述符????
- 我们在使用C语言用fopen()会返回一个文件指针,这个文件指针就代表这个这个文件
- 在Linux中,我们使用sokcet()函数打开一个socket文件,会返回一个socket描述符,这个描述符就代表着这个socket。描述符也称描述字
- ?功能:?bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket
- ?#include< sys/types.h> ?
- ?#include<
sys/socket.h>
?
int bind(int sockfd, const struct sockaddr*addr, socklen_taddrlen);
三、sendto()函数
- ?参数1: 服务端的socket描述符?
- ?参数2:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址(IP、端口号)?
- ?参数3:对应的地址的长度。服务器在启动的时候都会绑定一个地址(如ip地址+端口号)?
?返回值(int类型)?
- ?建立成功:成功返回0?
- ?建立失败:返回-1,并设置errno变量的值?
- #include < sys/types.h>
- #include < sys/socket.h>
- 发送数据
int sendto(int sockfd, const void * buf, size_t len, int flags, const struct sockaddr * dest_addr, socklen_t addrlen);
四、recvfrom()函数
- ?参数1:?自己的socket描述符
- ?参数2:?要发送的数据的起始地址
- ?参数3:?发送的数据大小
- ?参数4:?一般情况下为0
- ?参数5:?发送到的目的地址
- ?参数6:?地址长度
?返回值(ssize_t类型)?
- ?传递成功:返回发送的数据的字节大小?
- ?传递失败:返回-1,并设置errno变量的值?
- #include< unistd.h>
- 接收数据
int recvfrom(int sockfd, void * buf, size_t len, int flags, struct sockaddr * src_addr, socklen_t * addrlen);
五、close()函数
- ?参数1:?自己的socket描述符
- ?参数2:?接收到的数据的存放位置
- ?参数3:?接受数据的大小
- ?参数4:?一般情况下为0
- ?参数5:?数据来自于哪个地址
- ?参数6:?参数5地址的长度
?返回值(ssize_t类型)?
- ?成功:返回接收的数据的字节大小?
- ?失败:返回-1,并设置errno变量的值?
- ?当对等机执行有序关闭时,返回值将为0?
- 关闭相应的socket描述符
- #include <
unistd.h>
int close(int fd);
六、sendto和recvfrom最后一个参数的注意事项
- ? 参数:对应的socket描述符?
七、代码演示
因此这两个函数的最后一个参数在使用时一定要注意!!!!
- ?sendto最后一个参数的类型是socklen_t类型?
- ?recvfrom最后一个参数的类型是socklen_t*类?
?案例?
?sendto可以使用?
- ?struct sockaddr_in local; ?
- ?int len=sizeof(local); ?
- ?socklen_taddr_len=sizeof(local); ?
?recvfrom可以使用?
- ?sendto(...,..,..,len); ?
- ?sendto(...,..,..,addr_len); ?
- ?sendto(...,..,..,& len); ?
- ?sendto(...,..,..,& addr_len); ?
服务端
#include < stdio.h>
#include< sys/types.h>
#include< sys/socket.h>
#include< netinet/in.h>
#include< arpa/inet.h>
#include< string.h>
int main( int argc,char *argv[] )
if(argc!=3)
printf("Please Enter %s [IP] [PORT]\\n",argv[0]);
return 1;
//Create Socket
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock< 0)
printf("Create Socket error\\n");
return 2;
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(atoi(argv[2]));
local.sin_addr.s_addr=inet_addr(argv[1]);
//bind
if(bind(sock,(struct sockaddr*)& local,sizeof(local))< 0)
printf("Bind Error\\n");
close(sock);
return 3;
//recvfrom and sendto
int done=0;
struct sockaddr_in peer;
int len=sizeof(peer);
char buf[1024];
while(!done)
memset(buf,\\0,sizeof(buf));
recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr*)& peer,& len);
printf("get a clien ,socket:%s:%d\\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
printf("client say:%s\\n",buf);
sendto(sock,buf,sizeof(buf),0,(struct sockaddr*)& peer,len);
close(sock);
return 0;
?
客户端
#include < stdio.h>
#include < sys/types.h>
#include < sys/socket.h>
#include < string.h>
#include < arpa/inet.h>
#include < netinet/in.h>
int main( int argc,char *argv[] )
if(argc!=3)
printf("Please Enter %s [IP] [PORT]\\n",argv[0]);
return 1;
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock< 0)
perror("Create Socket Error:");
return 2;
struct sockaddr_in remote;
remote.sin_family=AF_INET;
remote.sin_port=htons(atoi(argv[2]));
remote.sin_addr.s_addr=inet_addr(argv[1]);
int done=0;
struct sockaddr_in peer;
int len=sizeof(peer);
char buf[1024];
while(!done)
memset(buf,\\0,sizeof(buf));
printf("Please enter:");
fflush(stdout);
ssize_t _s=read(0,buf,sizeof(buf)-1);
if(_s> 0)
buf[_s-1]=\\0;
sendto(sock,buf,sizeof(buf),0,(struct sockaddr*)& remote,sizeof(remote));
memset(buf,\\0,sizeof(buf));
recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr*)& peer,& len);
printf("server echo:%s,socket :%s:%d\\n",buf,inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
close(sock);
return 0;
?
【Linux(程序设计):42---UDP网络编程(单播)】
推荐阅读
- docker镜像创建 2 ——实战(SSHDLNMP)
- ZooKeeper客户端源码——向服务端建立连接+会话建立+心跳保持长连接
- Linux系统编程应用 V4L2编程基础
- Linux(程序设计):02---make与Makefile的设计与应用
- Linux(程序设计):05---gcc的基本用法
- Linux(程序设计):06---动态函数库与静态函数库(ldconfigldd命令与/etc/ld.so.conf)
- 服务/软件管理(06---Linux查看主机路由(route命令))
- Circle Linux镜像在阿里云镜像站首发上线
- 服务/软件管理(07---Linux下查看MAC与ARP table(arp命令))