一、绪言
udp是一种面向非连接,不可靠的通讯协议,相对于tcp来说,虽然可靠性不及,但传输效率较高。所以在网络上仍有很大的用途。这几日需要了解下udp通讯的过程,上网发现这方面的资料还挺少。于是仔细的翻找了下msdn,基本上搞清楚了udp通讯的过程。做了一个测试的例子。希望对大家有帮助。
二、udp的通讯过程
server端: open a socket(socket)--->name the socket(bind)--->send and receive data(sendto recvfrom)--->close socket(closesocket)
client端: open a socket(socket)---------------------------->send and receive data(sendto recvfrom)--->close socket(closesocket)
server端无需listen,client端无需connect,因此udp中server和client的区别相对较模糊。只要调用sendto和recvfrom就可以给指定的地址收发数据,但并不保证收发的数据的完整性和可靠性。
三、示例
udpserver主要代码:
01.
void
main()
02.
{
03.
SOCKET socket1;
04.
05.
InitWinsock();
06.
struct
sockaddr_in local;
07.
struct
sockaddr_in from;
08.
int
fromlen =
sizeof
(from);
09.
local.sin_family=AF_INET;
10.
local.sin_port=htons(1000);
///监听端口
11.
local.sin_addr.s_addr=INADDR_ANY;
///本机
12.
13.
socket1=socket(AF_INET,SOCK_DGRAM,0);
14.
bind(socket1,(
struct
sockaddr*)&local,
sizeof
local);
15.
while
(1)
16.
{
17.
char
buffer[1024]=
"\0"
;
18.
printf
(
"waiting for message from others-------------\n"
);
19.
if
(recvfrom(socket1,buffer,
sizeof
buffer,0,(
struct
sockaddr*)&from,&fromlen)!=SOCKET_ERROR)
20.
{
21.
printf
(
"Received datagram from %s--%s\n"
,inet_ntoa(from.sin_addr),buffer);
22.
给cilent发信息
23.
sendto(socket1,buffer,
sizeof
buffer,0,(
struct
sockaddr*)&from,fromlen);
24.
25.
}
26.
Sleep(500);
27.
}
28.
closesocket(socket1);
29.
}
udpcilent主要代码:
01.
void
main()
02.
{
03.
SOCKET socket1;
04.
05.
InitWinsock();
06.
struct
sockaddr_in server;
07.
int
len =
sizeof
(server);
08.
server.sin_family=AF_INET;
09.
server.sin_port=htons(1000);
///server的监听端口
10.
server.sin_addr.s_addr=inet_addr(
"168.168.0.10"
);
///server的地址
11.
12.
socket1=socket(AF_INET,SOCK_DGRAM,0);
13.
while
(1)
14.
{
15.
char
buffer[1024]=
"\0"
;
16.
printf
(
"input message\n"
);
17.
scanf
(
"%s"
,buffer);
18.
if
(
strcmp
(buffer,
"bye"
)==0)
19.
break
;
20.
if
(sendto(socket1,buffer,
sizeof
buffer,0,(
struct
sockaddr*)&server,len)!=SOCKET_ERROR)
21.
{
22.
if
(recvfrom(socket1,
23.
buffer,
24.
sizeof
buffer,
25.
0,
26.
(
struct
sockaddr*)&server,&len) != SOCKET_ERROR)
27.
printf
(
"rece from server:%s\n"
,buffer);
28.
}
29.
}
30.
closesocket(socket1);
31.
}
四、结束语
udp通讯比tcp简单了很多,在数据可靠性不是很高的情况下,有使用的价值。
两段网上抄的例子, 再加上一些特别的回复. 主要用于自动查找服务器, 方便DEBUG的.
流程是由客户端进行广播, 服务器收到广播后回复自己的IP给客户端, 实现客户端自动查找服务器使用的. 之前发的测试程序被抱怨要慢慢输入服务器IP, 现在搞个自动查找的, 不过没搞完....
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
// UDPBroadcastSend.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
using
namespace
std;
int
_tmain(
int
argc, _TCHAR* argv[])
{
SOCKET sock;
sockaddr_in addrto;
WSADATA wsdata;
bool
bsocket;
char
smsg[100] = {0};
cout<<
"input what message to send\n:"
<
cin>>smsg;
//启动SOCKET库,版本为2.0
WSAStartup(0x0202,&wsdata);
sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
bsocket=
true
;
//然后赋值给地址,用来从网络上的广播地址接收消息;
addrto.sin_family=AF_INET;
addrto.sin_addr.s_addr=INADDR_BROADCAST;
addrto.sin_port=htons(9000);
bool
opt=
true
;
//设置该套接字为广播类型,
setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(
char
FAR *)&opt,
sizeof
(opt));
int
nlen=
sizeof
(addrto);
char
buf[100] = {0};
while
(1)
{
addrto.sin_family=AF_INET;
addrto.sin_addr.s_addr=INADDR_BROADCAST;
addrto.sin_port=htons(9000);
Sleep(1000);
//从广播地址发送消息
int
ret=sendto(sock,smsg,
strlen
(smsg) + 1,0,(sockaddr*)&addrto,nlen);
if
(ret==SOCKET_ERROR)
{
printf
(
"%d/n"
,WSAGetLastError());
}
else
{
printf
(
"It'sock OK.\n"
);
}
ret = recvfrom( sock, buf,
sizeof
(buf), 0, (sockaddr*)&addrto, &nlen );
if
(SOCKET_ERROR == ret)
{
printf
(
"error on recv after send!\n"
);
}
else
{
printf
(
"recv after send: %s\n"
, buf);
}
}
return
0;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
// UDPBroadcastRecv.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
int
_tmain(
int
argc, _TCHAR* argv[])
{
SOCKET sock;
sockaddr_in from,a;
WSADATA wsdata;
bool
optval;
//启动SOCKET库,版本为2.0
WSAStartup(0x0202,&wsdata);
optval=
true
;
//然后赋值给两个地址,一个用来绑定套接字,一个用来从网络上的广播地址接收消息;
a.sin_family=AF_INET;
a.sin_addr.s_addr=INADDR_ANY;
a.sin_port=htons(9000);
from.sin_family=AF_INET;
from.sin_addr.s_addr=INADDR_BROADCAST;
from.sin_port=htons(5050);
int
fromlength=
sizeof
(SOCKADDR);
//用UDP初始化套接字
sock=socket(AF_INET,SOCK_DGRAM,0);
// 设置该套接字为广播类型,
setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(
char
FAR *)&optval,
sizeof
(optval));
// 把该套接字绑定在一个具体的地址上
bind(sock,(sockaddr *)&a,
sizeof
(sockaddr_in));
char
buf[256];
while
(1)
{
//从广播地址接收消息,注意用来绑定的地址和接收消息的地址是不一样的
recvfrom(sock,buf,256,0,(
struct
sockaddr FAR *)&from,(
int
FAR *)&fromlength);
//Sleep(2000);
printf
(
"%sock\n"
,buf);
sendto( sock, buf,
strlen
(buf) + 1, 0, (
struct
sockaddr FAR *)&from, fromlength );
ZeroMemory(buf,256);
}
return
0;
}
http://blog.sina.com.cn/s/blog_4fe4477501018697.html
|