目录

 

1.UDP

(1)recvfrom

(2)sendto

2.广播组播

1.广播

2.setsockopt

3.组播

1.UDP

 UDP协议与TCP协议有本质的区别

区别就在于TCP每次传输之前都已一对一的建立连接,通过三次握手与四次挥手来实现连接与断开连接,数据传输过程中数据丢失,错误都会重新发送一份数据来代替之前错误的那一份数据,保证了传输的可靠性,但是传输速度比较低

UDP就不存在这个问题,UDP实现的通讯不需要提前连接,只要直到对方的IP端口号,就可以发送数据,而且断开也不会对对方产生任何影响,可以多个客户端连接一个服务器。

UDP的数据收发与TCP锁调用的函数接口不一样,因为没有提前连接,所以每次发送与接收都需要知道对方的IP与端口。

(1)recvfrom

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

功能:     接收数据

参数:     sockfd:数据报套接字,sockfd的返回值     buf:储存的数组,内存地址     len:数据的大小     flags:0     src_addr:发送端的结构体的地址     addrlen:发送端的结构体长度的地址

返回值:     成功返回接受的字节数,失败返回-1

(2)sendto

#include #include         size_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

功能:     发送数据

参数:     sockfd:数据报套接字,sockfd的返回值     buf:储存的数组,内存地址     len:数据的大小     flags:0     src_addr:接收端的结构体的地址     addrlen:接收端的结构体长度

返回值:     成功返回发送的字节数,失败返回-1

UDP:无连接.

多个客户端可以发送消息给服务器

 发送端:

/*===============================================

* 文件名称:server_udp.c

* 创 建 者:

* 创建日期:2022年08月17日

* 描 述:

================================================*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

int main(int argc, char *argv[])

{ /*

if(argc<2)

{

printf("输入要发送的ip地址\n");

return -1;

} */

int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字

if(sockfd<0)

{

perror("sockfd");

return -1;

}

struct sockaddr_in server,client;//创建结构体来保存客户端与服务器的数据

server.sin_family=AF_INET;

server.sin_port=htons(8888);

server.sin_addr.s_addr=inet_addr("0");

int n=sizeof(server);

char buf[64]={0};

int m=sizeof(server);

while(1)

{

fgets(buf,sizeof(buf),stdin);//从终端输入数据

buf[strlen(buf)-1]='\0';//去除多读到的回车

sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&server,m);//发送数据

memset(buf,0,sizeof(buf));

}

close(sockfd);

return 0;

}

接收端:

/*===============================================

* 文件名称:server_udp.c

* 创 建 者:

* 创建日期:2022年08月17日

* 描 述:

================================================*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

int main(int argc, char *argv[])

{

int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字

if(sockfd<0)

{

perror("sockfd");

return -1;

}

struct sockaddr_in server,client;//创建结构体来保存客户端与服务器的数据

server.sin_family=AF_INET;

server.sin_port=htons(8888);

server.sin_addr.s_addr=inet_addr("0");

int n=sizeof(server);

int ret = bind(sockfd,(struct sockaddr *)&server,n);//绑定套接字

if(ret<0)

{

perror("bind");

}

char buf[64]={0};

int m=sizeof(client);

while(1)

{

int n=recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&client,&m);

printf("n=%d",n);

printf("clinet IP=%s client port=%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));//打印发送端的数据

printf("message:%s\n",buf);

memset(buf,0,sizeof(buf));

}

close(sockfd);

return 0;

}

运行结果

2.广播组播

1.广播

前面介绍的数据包发送方式只有一个接收方,称为单播

如果同时发给局域网中的所有主机,称为广播

网段中最大的地址称为广播地址,例如,192.168.22.0网段的广播地址为192.068.22.255,向此地址发送数据会被该网段中的所有主机接收

最大的广播是255.255.255.255.

广播特点:同时发送给局域网中的所有主机 UDP

发送广播消息:(client)

1.socket(AF_INET, SOCK_DGRAM, 0);

2.struct sockaddr_in argv[1] //向广播地址发送 //192.168.2.255

3.setsockopt //开广播权限

4.sendto (如果不开权限,会报错)

接收广播消息:(server)

1.socket(AF_INET, SOCK_DGRAM, 0);

2.struct sockaddr_in serveraddr;

3.bind //"0"地址 or 广播地址(只能收广播消息)

4.recvfrom 组播特点:既可以发送多个

广播发送端:

/*===============================================

* 文件名称:server_udp.c

* 创 建 者:

* 创建日期:2022年08月17日

* 描 述:

================================================*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

/*

void *recv_data(void *arg)

{

int sockfd= *(int *)arg;

char buf[64]={0};

struct sockaddr_in server,client;

server.sin_family=AF_INET;

server.sin_port=htons(7777);

server.sin_addr.s_addr=inet_addr("0");

int n=sizeof(server);

while(1)

{

recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&client,&n);

printf("message:%s\n",buf);

memset(buf,0,sizeof(buf));

}

}

*/

int main(int argc, char *argv[])

{

if(argc<2)

{

printf("输入要发送的ip地址\n");

return -1;

}

int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字

if(sockfd<0)

{

perror("sockfd");

return -1;

}

/*

pthread_t tid;

pthread_create(&tid,NULL,recv_data,(void *)&sockfd);

pthread_detach(tid);

*/

int on=1;//开启广播权限

int k = setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));

if(k<0)

{

perror("setsockopt");

return -1;

}

struct sockaddr_in server,client;//创界结构体保存输入输出端的信息

server.sin_family=AF_INET;

server.sin_port=htons(8888);

server.sin_addr.s_addr=inet_addr(argv[1]);

int n=sizeof(server);

char buf[64]={0};

int m=sizeof(client);

while(1)

{

fgets(buf,sizeof(buf),stdin);//从终端输入

buf[strlen(buf)-1]='\0';

sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&server,m);//发送到接收端

memset(buf,0,sizeof(buf));

}

close(sockfd);

return 0;

}

广播接收端:

/*===============================================

* 文件名称:server_udp.c

* 创 建 者:

* 创建日期:2022年08月17日

* 描 述:

================================================*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

/*

void *recv_data(void *arg)

{

int sockfd= *(int *)arg;

char buf[64]={0};

struct sockaddr_in server,client;

server.sin_family=AF_INET;

server.sin_port=htons(8888);

server.sin_addr.s_addr=inet_addr("0");

int n=sizeof(server);

while(1)

{

recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&client,&n);

printf("message:%s\n",buf);

memset(buf,0,sizeof(buf));

}

}

*/

int main(int argc, char *argv[])

{

int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字

if(sockfd<0)

{

perror("sockfd");

return -1;

}

/*

//创建线程

pthread_t tid;

pthread_create(&tid,NULL,recv_data,(void *)&sockfd);

pthread_detach(tid);

*/

struct sockaddr_in server,client;//创建结构体保存两端的信息

server.sin_family=AF_INET;

server.sin_port=htons(8888);

server.sin_addr.s_addr=inet_addr("0");

int n=sizeof(server);

int ret = bind(sockfd,(struct sockaddr *)&server,n);//绑定套接字

if(ret<0)

{

perror("bind");

}

char buf[64]={0};

int m=sizeof(client);

while(1)

{

recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&client,&m);//接收信息

printf("clinet IP=%s client port=%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));//打印发送端的信息

printf("message:%s\n",buf);

memset(buf,0,sizeof(buf));

}

close(sockfd);

return 0;

}

广播结果;

2.setsockopt

#include          #include

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

功能:修改套接字的属性 参数:     sockfd:数据报套接字,sockfd的返回值     level:属性设置             SOL_SOCKET:广播属性             IPPROTO_IP:组播属性          optname    :具体的属性修改,见以下属性设置表         optval:广播时,填入on的地址,组播时,填入结构体的地址     optlen:广播时,填入on的长度,组播时,填入结构体的长度      返回值:     成功返回0,失败返回-1

属性设置表:level SOL_SOCKET ------------------------------------------------ 参数optname 宏的作用 对应参数optaval的类型 SO_BROADCAST 允许发送广播数据 int SO_DEBUG 允许调试 int SO_DONTROUTE 不查找路由 int SO_ERROR 获得套接字错误 int SO_KEEPALIVE 保持连接 int SO_LINGER 延迟关闭连接 struct linger SO_OOBINLINE 带外数据放入正常数据流 int SO_RCVBUF 接收缓冲区大小 int SO_SNDBUF 发送缓冲区大小 int SO_RCVLOWAT 接收缓冲区下限 int SO_SNDLOWAT 发送缓冲区下限 int SO_RCVTIMEO 接收超时 struct timeval SO_SNDTIMEO 发送超时 struct timeval SO_REUSEADDR 允许重用本地地址和端口 int SO_TYPE 获得套接字类型 int SO_BSDCOMPAT 与BSD系统兼容 int ====================================================== IPPROTO_IP ------------------------------------------------------ IP_ADD_MEMBERSHIP 加入到组播组中 struct ip_mreq IP_MULTICAST_IF 允许开启组播报文的接口 struct ip_mreq      eg:     广播,打开广播权限              int on=1;     int k = setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));          组播,把指定ip加入到指定组播中          struct ip_mreqn mreq;     mreq.imr_multiaddr.s_addr=inet_addr("224.10.10.10");     mreq.imr_address.s_addr=inet_addr("0");          setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));

3.组播

组播特点:既可以发送多个主机, 又避免像广播一样造成广播风暴 UDP

 组播地址:

224.0.0.1~239.255.255.255

发送组播消息:(client)

1.socket

2.struct sockaddr_in argv[1]//向组播地址发送 //224.10.10.10

3.sendto

接收组播消息:(server) man 7 ip

1.socket

2.struct sockaddr_in serveraddr;

3.struct ip_mreqn mreq; // 组播地址 + "0"地址

4.setsockopt //加入多播组

5.bind

6.recvfrom

struct ip_mreqn {

struct in_addr imr_multiaddr; // IP multicast group address

struct in_addr imr_address; //IP address of local interface

int imr_ifindex; //interface index

};

组播发送端:

/*===============================================

* 文件名称:server_udp.c

* 创 建 者:

* 创建日期:2022年08月17日

* 描 述:

================================================*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

int main(int argc, char *argv[])

{

if(argc<2)

{

printf("输入要发送的ip地址\n");

return -1;

}

int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字

if(sockfd<0)

{

perror("sockfd");

return -1;

}

struct sockaddr_in server,client; //创建结构体存储发送端,接收端的信息

server.sin_family=AF_INET;

server.sin_port=htons(8888);

server.sin_addr.s_addr=inet_addr(argv[1]);

int n=sizeof(server);

char buf[64]={0}; //缓冲区

int m=sizeof(client);

while(1)

{

fgets(buf,sizeof(buf),stdin); //从终端输入

buf[strlen(buf)-1]='\0'; //处理输入的回车

sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&server,m);//发送数据

memset(buf,0,sizeof(buf));//清空缓冲区

}

close(sockfd);

return 0;

}

组播接收端;

/*===============================================

* 文件名称:server_udp.c

* 创 建 者:

* 创建日期:2022年08月17日

* 描 述:

================================================*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

int main(int argc, char *argv[])

{

int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字

if(sockfd<0)

{

perror("sockfd");

return -1;

}

struct sockaddr_in server,client;//创建结构体来存储发送端与接收端的信息

server.sin_family=AF_INET;

server.sin_port=htons(8888);

server.sin_addr.s_addr=inet_addr("0");

int n=sizeof(server);

struct ip_mreqn mreq;

mreq.imr_multiaddr.s_addr=inet_addr("224.10.10.10");

mreq.imr_address.s_addr=inet_addr("0");

setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));//把"0"加入到组“224.10.10.10”中

int ret = bind(sockfd,(struct sockaddr *)&server,n);//绑定套接字

if(ret<0)

{

perror("bind");

}

char buf[64]={0}; //缓冲区

int m=sizeof(client);

while(1)

{

recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&client,&m);//接收数据

printf("clinet IP=%s client port=%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));//打印发送端的信息

printf("message:%s\n",buf);//打印数据

memset(buf,0,sizeof(buf));

}

close(sockfd);

return 0;

}

运行结果

 

参考阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: