您的位置:首页 > 其它

UDP sendto和recvfrom使用详解

2015-04-04 11:19 323 查看





在网络编程中,UDP运用非常广泛。很多网络协议是基于UDP来实现的,如SNMP等。大家常常用到的局域网文件传输软件飞鸽传书也是基于UDP实现的。

本篇文章跟大家分享linux下UDP的使用和实现,主要介绍下sendto()和recvfrom()两个函数的使用,以及INADDR_ANY的说明,并在最后展示了一个经过自己测试可用的UDP Server和UDP Client的代码示例。

头文件

1
#include
<sys/types.h>
2
#include
<sys/socket.h>
函数原型

1
int
sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
2
3
int
recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
函数说明

sendto(),是把UDP数据报发给指定地址;recvfrom()是从指定地址接收UDP数据报。

参数说明

\s:socket描述符。

\buf: UDP数据报缓存地址。

\len:UDP数据报长度。

\flags: 该参数一般为0。

\to:sendto()函数参数,struct sockaddr_in类型,指明UDP数据发往哪里报。

\tolen:对方地址长度,一般为:sizeof(struct sockaddr_in)。

\fromlen:recvfrom()函数参数,struct sockaddr_in类型,指明从哪里接收UDP数据报。

函数返回值

对于sendto()函数,成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。

对于recvfrom()函数,成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。

struct sockaddr_in结构体

该结构体的定义如下:

01
/*
Structure describing an Internet (IP) socket address. */
02
#define
__SOCK_SIZE__ 16/* sizeof(struct sockaddr)*/
03
struct
sockaddr_in {
04
sa_family_t
sin_family; /* Address family */
05
__be16
sin_port; /* Port number*/
06
struct
in_addrsin_addr; /* Internet address */
07
08
/*
Pad to size of `struct sockaddr'. */
09
unsigned
char __pad[__SOCK_SIZE__ - sizeof(short int) -
10
sizeof(unsigned
short int) - sizeof(struct in_addr)];
11
};
其中,sin_family指明地址族,一般使用AF_INET:

1
#define
AF_INET 2 /* Internet IP Protocol */
sin_port:指明UDP端口;sin_addr指明IP地址:

1
/*
Internet address. */
2
struct
in_addr {
3
__be32
s_addr;
4
};
INADDR_ANY说明

INADDR_ANY,是个特殊IP地址 ,表示任务的IP地址,作为服务器端的时候经常要用到。对于它的解释,摘用下面一段英文(来自于:http://www.cs.cmu.edu/~srini/15-441/F01.full/www/assignments/P2/htmlsim_split/node18.html):

When you wrote your simple FTP server in project 1, you probably bound your listening socket to the special IP address INADDR_ANY. This allowed your program to work
without knowing the IP address of the machine it was running on, or, in the case of a machine with multiple network interfaces, it allowed your server to receive packets destined to any of the interfaces. In reality, the semantics of INADDR_ANY are
more complex and involved.

In the simulator, INADDR_ANY has the following semantics: When receiving, a socket bound to this address receives packets from all interfaces.
For example, suppose that a host has interfaces 0, 1 and 2. If a UDP socket on this host is bound using INADDR_ANY and udp port 8000, then the socket will receive
all packets for port 8000 that arrive on interfaces 0, 1, or 2. If a second socket attempts to Bind to port 8000 on interface 1, the Bind will fail since the first socket already “owns” that port/interface.

When sending, a socket bound with INADDR_ANY binds to the default IP address, which is that of the lowest-numbered interface.

大概的意思就是,作为接收端,当你调用bind()函数绑定IP时使用INADDR_ANY,表明接收来自任意IP、任意网卡的发给指定端口的数据。作为发送端,当用调用bind()函数绑定IP时使用INADDR_ANY,表明使用网卡号最低的网卡进行发送数据,也就是UDP数据广播。

关于UDP数据报

UDP都是以数据报的形式进行发送和接收的,而TCP是以数据流的形式进行发送和接收的。数据报和数据流,这两者要区分开来。

UDP Server和Client源码实例

UDP Server:

01
#include
<sys/types.h>
02
#include
<sys/socket.h>
03
#include
<netinet/in.h>
04
#include
<arpa/inet.h>
05
#include
<unistd.h>
06
#include
<stdlib.h>
07
#include
<string.h>
08
#include
<stdio.h>
09
10
#define
UDP_TEST_PORT 50001
11
12
int
main(
int
argC,
char
*
arg[])
13
{
14
struct
sockaddr_in
addr;
15
int
sockfd,
len = 0;
16
int
addr_len
=
sizeof
(
struct
sockaddr_in);
17
char
buffer[256];
18
19
/*
建立socket,注意必须是SOCK_DGRAM */
20
if
((sockfd
= socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
21
perror
(
"socket"
);
22
exit
(1);
23
}
24
25
/*
填写sockaddr_in 结构 */
26
bzero(&addr,
sizeof
(addr));
27
addr.sin_family
= AF_INET;
28
addr.sin_port
= htons(UDP_TEST_PORT);
29
addr.sin_addr.s_addr
= htonl(INADDR_ANY) ;
//
接收任意IP发来的数据
30
31
/*
绑定socket */
32
if
(bind(sockfd,
(
struct
sockaddr
*)&addr,
sizeof
(addr))<0)
{
33
perror
(
"connect"
);
34
exit
(1);
35
}
36
37
while
(1)
{
38
bzero(buffer,
sizeof
(buffer));
39
len
= recvfrom(sockfd, buffer,
sizeof
(buffer),
0,
40
 
(
struct
sockaddr
*)&addr ,&addr_len);
41
/*
显示client端的网络地址和收到的字符串消息 */
42
printf
(
"Received
a string from client %s, string is: %s\n"
,
43
inet_ntoa(addr.sin_addr),
buffer);
44
/*
将收到的字符串消息返回给client端 */
45
sendto(sockfd,buffer,
len, 0, (
struct
sockaddr
*)&addr,addr_len);
46
}
47
48
return
0;
49
}
50
51
//
----------------------------------------------------------------------------
52
//
End of udp_server.c
UDP Client:

01
#include
<sys/types.h>
02
#include
<sys/socket.h>
03
#include
<netinet/in.h>
04
#include
<arpa/inet.h>
05
#include
<unistd.h>
06
#include
<stdlib.h>
07
#include
<string.h>
08
#include
<stdio.h>
09
10
#define
UDP_TEST_PORT 50001
11
#define
UDP_SERVER_IP "127.0.0.1"
12
13
int
main(
int
argC,
char
*
arg[])
14
{
15
struct
sockaddr_in
addr;
16
int
sockfd,
len = 0;
17
int
addr_len
=
sizeof
(
struct
sockaddr_in); 
18
char
buffer[256];
19
20
/*
建立socket,注意必须是SOCK_DGRAM */
21
if
((sockfd
= socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
22
perror
(
"socket"
);
23
exit
(1);
24
}
25
26
/*
填写sockaddr_in*/
27
bzero(&addr,
sizeof
(addr));
28
addr.sin_family
= AF_INET;
29
addr.sin_port
= htons(UDP_TEST_PORT);
30
addr.sin_addr.s_addr
= inet_addr(UDP_SERVER_IP);
31
32
while
(1)
{
33
bzero(buffer,
sizeof
(buffer));
34
35
printf
(
"Please
enter a string to send to server: \n"
);
36
37
/*
从标准输入设备取得字符串*/
38
len
= read(STDIN_FILENO, buffer,
sizeof
(buffer));
39
40
/*
将字符串传送给server端*/
41
sendto(sockfd,
buffer, len, 0, (
struct
sockaddr
*)&addr,addr_len);
42
43
/*
接收server端返回的字符串*/
44
len
= recvfrom(sockfd, buffer,
sizeof
(buffer),
0,
45
 
(
struct
sockaddr
*)&addr,&addr_len);
46
printf
(
"Receive
from server: %s\n"
,
buffer);
47
}
48
49
return
0;
50
}
51
52
//
----------------------------------------------------------------------------
53
//
End of udp_client.c
上述代码是经过验证可用的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: