JAVA socket编程 Datagram套接字 UDP协议(转)

 
查看文章
   
JAVA socket编程 Datagram套接字 UDP协议
2009-05-13 09:35

1 UDP套接字 

数据报(Datagram)是网络层数据单元在介质上传输信息的一种逻辑分组格式,它是一种在网络中传播的、独立的、自身包含地址信息的消息,它能否到达目的地、到达的时间、到达时内容是否会变化不能准确地知道。它的通信双方是不需要建立连接的,对于一些不需要很高质量的应用程序来说,数据报通信是一个非常好的选择。还有就是对实时性要求很高的情况,比如在实时音频和视频应用中,数据包的丢失和位置错乱是静态的,是可以被人们所忍受的,但是如果在数据包位置错乱或丢失时要求数据包重传,就是用户所不能忍受的,这时就可以利用UDP协议传输数据包。在Java的java.net包中有两个类DatagramSocket和DatagramPacket,为应用程序中采用数据报通信方式进行网络通信。 

使用数据包方式首先将数据打包,Java.net包中的DategramPacket类用来创建数据包。

数据包有,

一种用来,该数据包有要传递到的目的地址;

另一种数据包用来接收传递过来的数据包中的数据。要创建,通过DatagramPackett类的方法构造:
public DatagramPacket(byte ibuft[],int ilength) 传递数据包
public DatagramPacket( byte ibuft[],int ,int ilength) 接收数据包

ibuf[]为接受数据包的存储数据的缓冲区的长度,ilength为从传递过来的数据包中读取的字节数。当采用第一种构造方法时,接收到的数据从ibuft[0]开始存放,直到整个数据包接收完毕或者将ilength的字节写入ibuft为止。采用第二种构造方法时,接收到的数据从ibuft[offset]开始存放。。不过这是RuntimeException,不需要用户代码捕获。示范代码如下:
byte[ ] buffer=new byte[8912];
DatagramPacket datap=new DatagramPacket(buffer ,buffer.length( )); 

创建的构造方法为:
public DatagramPacket(byt ibuf[],int ilength,InetAddrss iaddr,int port)
public DatagramPacket(byt ibuf[],int offset , int ilength,InetAddrss iaddr,int port) 

iaddr为数据包要传递到的目标地址,port为目标地址的程序接受数据包的端口号(即目标地址的计算机上运行的客户程序是在哪一个端口接收服务器发送过来的数据包)。ibuf[]为要发送数据的存储区,以ibuf数组的offset位置开始填充数据包ilength字节,如果没有offset,则从ibuf数组的0位置开始填充。以下示范代码是要发送一串字符串: 

String s = new String("java networking");
byte[ ] data=s.getbytes();
int port=1024;
try{
InetAddress ineta= InetAddress.getByName(" 169.254.0.14");
DatagramPacket datap=new DatagramPacket
(data ,data.length( ),ineta,port);
}
catch(IOException e) {
}



数据包也是对象,也有操作方法用来,这是很有用的。其方法如下:

public InetAddress getAddress() 如果是发送数据包,则获得数据包要发送的目标地址,但是如果是接收数据包则返回发送此数据包的。

public byte[]getData() 

返回一个字节数组,其中是数据包的数据。如果想把字节数组转换成别的类型就要进行转化。如果想转化成String类型,可以进行以下的处理,设DatagramPacket datap为:
String s = new String(datap.getbytes()); 



public int getLength() 获得数据包中数据的字节数。

pubic int getPort( ) 返回数据包中的。 

发送和接收数据包还需要发送和接收数据包的,即DatagramSocket对象,DatagramSocket套接字在本地机器端口监听是否有数据到达或者将数据包发送出去。其构造方法如下。 


public DatagramSocket() 用本地机上任何一个可用的端口创建一个套接字,这个端口号是由系统随机产生的。使用方法如下: 

try{
DatagramSocket datas=new DatagramSocket( );
//发送数据包
}
catch(SocketException e){
}



这种构造方法没有指定端口号,可以用在客户端。如果构造不成功则触发SocketException异常。

public DatagramSocket(int port) 
用一个指定的端口号port创建一个套接字。 

当不能创建套接字时就抛出SocketException异常,其原因是指定的或者是试图的端口,但是又没有。 

2 实例:利用DatagramSocket查询端口占用情况 

我们可以利用这个异常探查本地机的端口号有没有服务。见示例12-9。
【程序源代码】 

1 // ==================== Program Description =====================
2 // 程序名称:示例12-9: UDPScan.java
3 // 程序目的:熟悉DatagramSocket的基本用法,查询端口的占用情况
4 //=========================================================
5 import java.net.*;

7 public class UDPScan
8 {
9 public static void main(String args[])
10 {
11 for (int port=1024;port<=65535;port++) {
12 try {
13 DatagramSocket server=new DatagramSocket(port);
14 server.close();
15 }
16 catch(SocketException e) {
17 System.out.println("there is a server in port "+port+".");
18 }
19 }
20 }
21 }



【程序输出结果】 

there is a server in port 1026.
there is a server in port 1028.
there is a server in port 1046.
there is a server in port 1900.



【程序注解】
在第11~19行我们用for循环以端口号为参数实例化DatagramSocket,其中端口号从1024到65535。如果在实例过程中出错,会抛出SocketException异常。我们根据这个异常就可以判断出哪些端口被占用,哪些还是空闲的。值得一提的是,我们在实例化了DatagramSocket后,调用了close()关闭它。作为一种好的作风,应该遵循。端口号在1024以下的系统可能会用到,比如HTTP默认为80端口,FTP默认为21端口,等等,所以我们从1024端口开始探查。 

套接字对象也有相应的方法,例如发送数据包的方法还有接收数据包的方法,介绍如下。

pubic void close() 当我们创建一个套接字后,用该方法关闭套接字。

public int getLocalPort() 返回本地套接字的正在监听的端口号。

public void receive(DatagramPacket p) 从网络上接收数据包并将其存储在DatagramPacket对象p中。p中的数据缓冲区必须足够大,。接收数据出错时会抛出IOException异常。

public Void Send(DatagramPacket p) 发送数据包,出错时会发生IOException异常。 

下面,我们详细解释在Java中实现客户端与服务器之间数据报通信的方法。
应用程序的工作流程如下: 

(1)首先要建立数据报通信的Socket,我们可以通过创建一个DatagramSocket对象实现它,在Java中DatagramSocket类有如下两种构造方法:

public DatagramSocket() 构造一个数据报socket,并使其与本地主机任一可用的端口连接。若打不开socket则抛出SocketException异常。

public DatagramSocket(int port) 构造一个数据报socket,并使其与本地主机指定的端口连接。若打不开socket或socket无法与指定的端口连接则抛出SocketException异常。 

(2)创建一个数据报文包,用来实现无连接的包传送服务。每个数据报文包用DatagramPacket类创建,DatagramPacket对象封装了数据报包数据、包长度、目标地址和目标端口。客户端要发送数据报文包,要调用DatagramPacket类以如下形式的构造函数创建DatagramPacket对象,将要发送的数据和包文目的地址信息放入对象之中。DatagramPacket(byte bufferedarray[],int length,InetAddress address,int port)即构造一个包长度为length的包传送到指定主机指定端口号上的数据报文包,参数length必须小于等于bufferedarry.length。 

DatagramPacket类提供了4个类获取信息:

public byte[] getData() 返回一个字节数组,包含收到或要发送的数据报中的数据。

public int getLength() 返回发送或接收到的数据的长度。

public InetAddress getAddress() 返回一个发送或接收此数据报包文的机器的IP地址。 



public int getPort() 返回发送或接收数据报的远程主机的端口号。 

(3)创建完DatagramSocket和DatagramPacket对象,就可以发送数据报文包了。发送是通过调用,它需要以DatagramPacket对象为参数,将刚才封装进DatagramPacket对象中的数据组成数据报发出。 

(4)当然,我们也可以接收数据报文包。为了接收从服务器返回的结果数据报文包,我们需要创建一个新的DatagramPacket对象,这就需要用到DatagramPacket的另一种构造方式DatagramPacket(byte bufferedarray[],int length),即只需指明存放接收的数据报的缓冲区和长度。调用DatagramSocket对象的报的工作,此时需要将上面创建的DatagramPacket对象作为参数,该方法会一直直到收到一个数据报文包,此时DatagramPacket的缓冲区中包含的就是接收到的数据,数据报文包中也包含发送者的IP地址,发送者机器上的端口号等信息。 

(5)处理接收缓冲区内的数据,获取服务结果。 

(6)当通信完成后,可以使用DatagramSocket对象的close()方法关闭数据报通信Socket。当然,Java会自动关闭Socket,DatagramSocket和DatagramPacket所占用的。但是作为一种良好的编程习惯,。 

3 实例:利用数据报通信的C/S程序
示例12-10给出了一个简单的利用数据报通信的客户端程序,它能够完成与服务器简单的通信。
【程序源代码】 

1 // ==================== Program Description ===================
2 // 程序名称:示例12-10: UDPServer.java
3 // 程序目的:创建UDP服务器
4 //=============================================================
5 import java.net.*;
6 import java.io.*;

8 public class UDPServer
9 {
10 static public void main(String args[])
11 {
12 try { 
13 DatagramSocket receiveSocket = new DatagramSocket(5000);
14 byte buf[]=new byte[1000];
15 DatagramPacket receivePacket=new DatagramPacket(buf,buf.length);
16 System.out.println("startinig to receive packet");
17 while (true)
18 { 
19 receiveSocket.receive(receivePacket);
20 String name=receivePacket.getAddress().toString();
21 System.out.println("\n来自主机:"+name+"\n端口:"
22 +receivePacket.getPort());
23 String s=new
String(receivePacket.getData(),0,receivePacket.getLength());
24 System.out.println("the received data: "+s);
25 }
26 }
27 catch (SocketException e) {
28 e.printStackTrace();
29 System.exit(1);
30 }
31 catch(IOException e) {
32 System.out.println("网络通信出现错误,问题在"+e.toString());
33 }
34 }
35 }



【程序输出结果】 

startinig to receive packet
来自主机:/166.111.172.20
端口:3456
the received data: hello! this is the client



【程序注解】
第13行和第15行分别实例化了一个DatagramSocket对象receiveSocket和一个DatagramPacket对象receivePacket,都是通过调用各自的构造函数实现的,为建立服务器做好准备。在while这个永久循环中,receiveSocket这个套接字始终尝试receive()方法接收DatagramPacket数据包,当接收到数据包后,就调用DatagramPacket的一些成员方法显示一些数据包的信息。在程序中调用了getAddress()获得地址,getPort()方法获得客户端套接字的端口,getData()获得客户端传输的数据。注意getData( )返回的是字节数组,我们把它转化为字符串显示。在第27~33行我们对程序中发生的SocketException和IOException异常进行了处理。
示例12-11是UDP客户端的程序。
【程序源代码】 

1 // ==================== Program Description ===================
2 // 程序名称:示例12-11: UDPClient.java
3 // 程序目的:创建UDP客户端
4 //=============================================================
5 import java.net.*;
6 import java.io.*;

8 public class UDPClient
9 {
10 public static void main(String args[])
11 {
12 try {
13 DatagramSocket sendSocket=new DatagramSocket(3456);
14 String string="asfdfdfggf";
15 byte[] databyte=new byte[100];
16 databyte=string.getBytes();
17 DatagramPacketsendPacket=new
DatagramPacket(databyte,string.length(), 
18 InetAddress.getByName("163.121.139.20"),
5000); 
19 sendSocket.send(sendPacket);
20 System.out.println("send the data: hello ! this is the client");
21 }
22 catch (SocketException e) {
23 System.out.println("不能打开数据报Socket,或数据报Socket无法与指定
24 端口连接!");
25 }
26 catch(IOException ioe) {
27 System.out.println("网络通信出现错误,问题在"+ioe.toString());
28 } 
29 }
30 }



【程序输出结果】
send the data: hello !this is the clientsend the data: hello !this is the client 

【程序注解】
第13行用DatagramSocket的构造函数实例化一个发送数据的套接字sendSocket。第17~18行实例化了一个DatagramPacket,其中数据包要发往的目的地是163.121.139.20,端口是5000。当构造完数据包后,就调用send( )方法将数据包发送出去。 

4 组播套接字 

在Java中,可以用java.net.MulticastSocket类组播数据。组播套接字是DatagramSocket的子类,定义如下:
public class MulticastSocket extends DatagramSocket 

构造方法有两个:
public MulticastSocket ( ) throws SocketException
public MulticastSocket (int port ) throws SocketException 

以上两个方法都是创建组播套接字,第一个方法没有端口号,第二个指定了端口号。
常用的方法如下:

public void joinGroup(InetAddress address) throws IOException 

建立了MulticastSocket对象后,为了发送或者接收组播包,必须用joinGroup方法加入一个组播组。若加入的不是组播地址将触发IOException异常。

public void leaveGroup(InetAddress address)throws IOException 

如果不想接收组播包了,就调用leaveGroup方法。程序就发信息到组播路由器,通知它向此用户发送数据。若想离开的地址不是组播地址就触发IOException异常。

public void send(DatagramPacket packet, byte, ttl) throws IOExceptin
发送组播包的方法与DatagramSocket发送数据相似。其中ttl是生存时间,大小在0~255之间。

public void receive(DatagramPacket p) 与DatagramSocket的接收方法没有差别。

public void setTimeToLive(int ttl )throws IOException 设置套接字发出的组播包中的默认ttl数值。

public int getTimeToLive( ) throws IOException 返回ttl数值。 

使用组播套接字发送数据的过程是首先用MulticastSocket()构造器创建MulticastSocket类,然后利用MulticastSocket类的joinGroup()方法加入一个组播组,之后创建DatagramPacket数据包,最后调用MulticastSocket类的send()方法发送组播包。
发送组播包的代码如下: 

try {
InetAddress address = InetAddress.getByName (www.mmm.net) ;
byte[ ] data=" java networking";
int port =5000;
DatagramPacket datap =new DatagramSocket 
(data ,data.length( ),address,port);
MulticastSocket muls =new MulticastSocket ( );
muls.send(datap );
}
catch(IOException ie) { 
}



使用组播套接字接收数据的过程是首先用MulticastSocket()构造器创建MulticastSocket类,然后利用MulticastSocket类的joinGroup()方法加入一个组播组,之后用receive()方法接收组播包。我们发现其过程与UDP包的过程很相似,区别是要加入一个组播组。 

5 实例:组播套接字C/S程序 

下面的程序示例12-12说明了组播套接字的基本用法。
【程序源代码】 

1 // ==================== Program Description ===================== 
2 // 程序名称:示例12-12: MulticastServer.java
3 // 程序目的:创建一个组播服务器
4 //==========================================================
5 import java.io.*;
6 import java.net.*;
7 import java.util.*;

9 class QuoteServerThread extends Thread 
10 {
11 protected DatagramSocket socket = null;
12 protected BufferedReader in = null;
13 protected boolean moreQuotes = true;
14 
15 public QuoteServerThread() throws IOException {
16 this("QuoteServerThread");
17 }
18 
19 public QuoteServerThread(String name) throws IOException {
20 super(name);
21 socket = new DatagramSocket(4445);
22 
23 try {
24 in = new BufferedReader(new FileReader("one-liners.txt"));
25 } catch (FileNotFoundException e) {
26 System.err.println("Could not open quote file. 
Serving time instead.");
27 }
28 }
29 
30 public void run() {
31 while (moreQuotes) {
32 try {
33 byte[] buf = new byte[256];
34 
35 // 获取请求
36 DatagramPacket packet = new DatagramPacket(buf, buf.length);
37 socket.receive(packet);
38 
39 // 进行响应
40 String dString = null;
41 if (in == null)
42 dString = new Date().toString();
43 else
44 dString = getNextQuote();
45 buf = dString.getBytes();
46 
47 // 向用户发送响应
48 InetAddress address = packet.getAddress();
49 int port = packet.getPort();
50 packet = new DatagramPacket(buf, buf.length, address, port);
51 socket.send(packet);
52 }
53 catch (IOException e) {
54 e.printStackTrace();
55 moreQuotes = false;
56 }
57 }
58 socket.close();
59 }
60 
61 protected String getNextQuote() {
62 String returnValue = null;
63 try {
64 if ((returnValue = in.readLine()) == null) {
65 in.close();
66 moreQuotes = false;
67 returnValue = "No more quotes. Goodbye.";
68 }
69 } catch (IOException e) {
70 returnValue = "IOException occurred in server.";
71 }
72 return returnValue;
73 }
74 }
75 
76 class MulticastServerThread extends QuoteServerThread 
77 {
78 private long FIVE_SECONDS = 5000;
79 
80 public MulticastServerThread() throws IOException {
81 super("MulticastServerThread");
82 }
83 
84 public void run() {
85 while (moreQuotes) {
86 try {
87 byte[] buf = new byte[256];
88 
89 // 构造引用
90 String dString = null;
91 if (in == null)
92 dString = new Date().toString();
93 else
94 dString = getNextQuote();
95 buf = dString.getBytes();
96 
97 // 发送
98 InetAddress group = InetAddress.getByName("136.122.133.1");
99 DatagramPacket packet =new
DatagramPacket(buf,buf.length,group, 
100 4446);
101 socket.send(packet);
102 
103 // 休眠
104 try {
105 sleep((long)(Math.random() * FIVE_SECONDS));
106 } 
107 catch (InterruptedException e) { }
108 } 
109 catch (IOException e) {
110 e.printStackTrace();
111 moreQuotes = false;
112 }
113 }
114 socket.close();
115 }
116 }
117 
118 public class MulticastServer {
119 public static void main(String[] args) throws java.io.IOException {
120 new MulticastServerThread().start();
121 }
122 }



【程序注解】
服务器程序由3个类组成:QuoteServerThread,MulticastServerThread和MulticastServer。它们的关系是:QuoteServerThread继承自线程类,而MulticastServerThread类继承自类QuoteServerThread。这个程序主要的部分在QuoteServerThread和MulticastServerThread。QuoteServerThread类有两个构造函数,其中在构造函数QuoteServerThread(String name)中,初始化了DatagramSocket套接字并打开了文件one-liners.txt,在这个文件中存有服务器发送的字符串。 

在QuoteServerThread类的run()函数中,服务器端套接字接收来自客户端的数据包,并从文件中读取数据,把信息发给客户端。 

MulticastServerThread类中重载了run( )方法,实现的功能基本相同,在发完服务器的信息后,用sleep( )函数停止处理了一个随机的时间。 

在MultiServer类中,用 new MulticastServerThread().start()开始服务器线程。我们现在只是关注其基本思想。 

示例12-13是UDP组播的客户端程序。
【程序源代码】 

1 // ==================== Program Description ===================== 
2 // 程序名称:示例12-13: MulticastClient.java
3 // 程序目的:UDP组播客户端
4 //====================>7��:示例1D====================================
5 import java.io.*;
6 import java.net.*;
7 import java.util.*;

9 public class MulticastClient 
10 {
11 public static void main(String[] args) throws IOException 
12 {
13 MulticastSocket socket = new MulticastSocket(4446);
14 InetAddress address = InetAddress.getByName("136.122.133.1");
15 socket.joinGroup(address);
16 DatagramPacket packet;
17 
18 for (int i = 0; i < 5; i++) 
19 {
20 byte[] buf = new byte[256];
21 packet = new DatagramPacket(buf, buf.length);
22 socket.receive(packet);
23 String received = new String(packet.getData());
24 System.out.println("Quote of the Moment: " + received);
25 }
26 
27 socket.leaveGroup(address);
28 socket.close();
29 }
30 }



【程序输出结果】 

Quote of the Moment: Give me ambiguity or give me something else.
Quote of the ME7��:示例1oment: I.R.S.: We've got what it takes to take what you've got!
Quote of the Moment: We are born naked, wet and hungry. Then things get worse.
Quote of the Moment: Make it idiot proof and someone will make a better idiot.
Quote of the Moment: He who laughs last thinks slowest!



【程序注解】
在客户端的main()方法中,第13行实例化了一个MulticastSocket对象socket,然后用join()方法加入了组播组136.122.133.1。在for循环中接收了5个数据包,并把数据包中的内容显示出来(第18~25行)。最后在第27行离开组播组(leaveGroup()),第28行关

posted @ 2012-02-11 23:18 喔、勒勒 阅读(144) 评论(0) 编辑

Java UDP通信(DatagramPacket类、DatagramSocket类、InetAddress类)(转)

一、DatagramPacket类:

如果把DatagramSocket比作创建的港口码头,那么DatagramPacket就是发送和接收数据的集装箱。
构造函数:一个用来接收数据,一个用来发送数据
public DatagramPacket(byte[] buf,int length) //接收数据
构造 DatagramPacket 用来接收长度为 ilength 的包。 
public DatagramPacket(byte[] buf,int length,InetAddress address,int port)
构造数据报文包用来把长度为 ilength 的包传送到指定宿主的指定的端口号。
getAddress() 
返回接收或发送此数据报文的机器的 IP 地址。 
getData() 
返回接收的数据或发送出的数据。 
getLength() 
返回发送出的或接收到的数据的长度。 
getPort() 
返回接收或发送该数据报文的远程主机端口号。

二、DatagramSocket类

此类表示用来发送和接收数据报包的套接字。 数据报套接字是包投递服务的发送或接收点。
DatagramSocket(int port)     创建数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket(int port, InetAddress laddr)     创建数据报套接字,将其绑定到指定的本地地址。

receive(DatagramPacket p) 
             从此套接字接收数据报包。 
void send(DatagramPacket p) 
             从此套接字发送数据报包。 
bind(SocketAddress addr) 
             将此 DatagramSocket 绑定到特定的地址和端口。 
void close() 
             关闭此数据报套接字。 
void connect(InetAddress address, int port) 
             将套接字连接到此套接字的远程地址。 
void connect(SocketAddress addr) 
             将此套接字连接到远程套接字地址(IP 地址 + 端口号)。 
void disconnect() 
             断开套接字的连接。 
getInetAddress() 
             返回此套接字连接的地址。 
InetAddress getLocalAddress() 
             获取套接字绑定的本地地址。

三、InetAddress类
InetAddress用于表示计算机IP地址的一个类,而在日常应用中的IP地址用"192.168.0.1",
"WWW.it315.org"等字符串格式表示的。
getByName方法
getHostAddress方法

四、UDP通信示例代码:

发送端代码UdpSend.java:

import java.net.*;

public class UdpSend {
          public static void main(String[] args) throws Exception{
            DatagramSocket ds=new DatagramSocket();
           String strInfo="Hello Taohx";
           ds.send(new DatagramPacket(strInfo.getBytes(),strInfo.length(),
                                    InetAddress.getByName("59.64.157.93"),3000));
           ds.close();            
       }
}

接收代码UdpRecv.java:

import java.net.*;
public class UdpRecv {
       public static void main(String[] args) throws Exception{
           DatagramSocket ds=new DatagramSocket(3000);
           byte [] buf=new byte[1024];
           DatagramPacket dp=new DatagramPacket(buf,1024);
           ds.receive(dp);
          String strInfo= new String(dp.getData(),0,dp.getLength())+
            " from "+dp.getAddress().getHostAddress()+":"+dp.getPort();
           System.out.println(strInfo);
           ds.close();
            
       }
}

注意:若发送中文信息时,因为中文字符占两个字节,故发送代码 ds.send要修改如下才可正确地发送中文信息,

ds.send(new DatagramPacket(strInfo.getBytes(),strInfo.getBytes().length,
                                   InetAddress.getByName("59.64.157.93"),3000));

***********************************************************************************************************

在Java中操纵UDP 

  使用位于JDK中Java.net包下的DatagramSocket和DatagramPacket类,可以非常方便地控制用户数据报文。 

  在描述它们之前,必须了解位于同一个位置的InetAddress类。InetAddress实现了Java.io. Serializable接口,不允许继承。它用于描述和包装一个Internet IP地址,通过三个方法返回InetAddress实例: 

getLocalhost():返回封装本地地址的实例。 

getAllByName(String host):返回封装Host地址的InetAddress实例数组。 

getByName(String host):返回一个封装Host地址的实例。其中,Host可以是域名或者是一个合法的IP地址。 

DatagramSocket类用于创建接收和发送UDP的Socket实例。和Socket类依赖SocketImpl类一样,DatagramSocket类的实现也依靠专门为它设计的DatagramScoketImplFactory类。DatagramSocket类有3个构建器: 

DatagramSocket():创建实例。这是个比较特殊的用法,通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。 

DatagramSocket(int port):创建实例,并固定监听Port端口的报文。 

DatagramSocket(int port, InetAddress localAddr):这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文。 

值得注意的是,在创建DatagramSocket类实例时,如果端口已经被使用,会产生一个SocketException的异常抛出,并导致程序非法终止,这个异常应该注意捕获。DatagramSocket类最主要的方法有4个: 

Receive(DatagramPacket d):接收数据报文到d中。receive方法产生一个“阻塞”。 

Send(DatagramPacket d):发送报文d到目的地。 

SetSoTimeout(int timeout):设置超时时间,单位为毫秒。 

Close():关闭DatagramSocket。在应用程序退出的时候,通常会主动释放资源,关闭Socket,但是由于异常地退出可能造成资源无法回收。所以,应该在程序完成时,主动使用此方法关闭Socket,或在捕获到异常抛出后关闭Socket。 

“阻塞”是一个专业名词,它会产生一个内部循环,使程序暂停在这个地方,直到一个条件触发。 

DatagramPacket类用于处理报文,它将Byte数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成Byte数组。应用程序在产生数据包是应该注意,TCP/IP规定数据报文大小最多包含65507个,通常主机接收548个字节,但大多数平台能够支持8192字节大小的报文。DatagramPacket类的构建器共有4个: 

DatagramPacket(byte[] buf, int length, InetAddress addr, int port):从Buf数组中,取出Length长的数据创建数据包对象,目标是Addr地址,Port端口。 

DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):从Buf数组中,取出Offset开始的、Length长的数据创建数据包对象,目标是Addr地址,Port端口。 

DatagramPacket(byte[] buf, int offset, int length):将数据包中从Offset开始、Length长的数据装进Buf数组。 

DatagramPacket(byte[] buf, int length):将数据包中Length长的数据装进Buf数组。 

DatagramPacket类最重要的方法就是getData()了,它从实例中取得报文的Byte数组编码。 

简单的实例说明 

{接收数据的服务器} 


byte[] buf = new byte[1000];

DatagramSocket ds = new DatagramSocket(12345);

//开始监视12345端口

DatagramPacket ip = new DatagramPacket(buf, buf.length);

//创建接收数据报的实例

while (true)

{

ds.receive(ip);

//阻塞,直到收到数据报后将数据装入IP中

System.out.println(new String(buf));

}


{发送数据的客户端} 


InetAddress target = InetAddress.getByName(“www.xxx.com“);

//得到目标机器的地址实例

DatagramSocket ds = new DatagramSocket(9999);

//从9999端口发送数据报

String hello = “Hello, I am come in!”;

//要发送的数据

byte[] buf = hello.getBytes();

//将数据转换成Byte类型

op = new DatagramPacket(buf, buf.length, target, 12345);

//将BUF缓冲区中的数据打包

ds.send(op);

//发送数据

ds.close();

//关闭连接

posted @ 2012-02-11 18:18 喔、勒勒 阅读(147) 评论(0) 编辑

Socket编程---使用无连接的数据报(UDP) 进行通信(转)

使用无连接的数据报(UDP) 进行通信

什么是Datagram?
数据报是网上传输的独立数据包 ,数据报是否能正确地到达目的地,到达的时间,顺序,内容的正确性均没有保障。
 
java中使用Datagram与DatagramPacket类
DatagramSocket类利用UDP协议来实现客户与服务器的Socket.
send():发送数据报
receive(): 接收数据报

 

 以下为流程

 



 

 

 

以下为简单示例,不含一些异常处理、判空处理。

 

一、服务器端

Java代码  收藏代码
  1. package com.network;  
  2.   
  3. import java.net.DatagramPacket;  
  4. import java.net.DatagramSocket;  
  5. import java.net.InetAddress;  
  6.   
  7. public class UDPServer  
  8. {  
  9.   
  10.     public static void main(String[] args)throws Exception  
  11.     {  
  12.         DatagramSocket datagramSocket = new DatagramSocket(5678);  
  13.           
  14.         byte[] buffer = new byte[100];  
  15.           
  16.         DatagramPacket packet = new DatagramPacket(buffer,100);  
  17.           
  18.         datagramSocket.receive(packet);  
  19.           
  20.         byte[] data = packet.getData();  
  21.           
  22.         int i = packet.getLength();  
  23.           
  24.         String content = new String(data,0,i);  
  25.           
  26.         System.out.println("content from client : " + content);  
  27.           
  28.         int length = content.length();  
  29.           
  30.         String strLength = String.valueOf(length);  
  31.           
  32.         byte[] b = strLength.getBytes();  
  33.           
  34.         InetAddress address = packet.getAddress();  
  35.           
  36.         int port = packet.getPort();  
  37.           
  38.         DatagramPacket packet2 = new DatagramPacket(b,b.length,address,port);  
  39.           
  40.         System.out.println("length: " + new String(b,0,b.length));  
  41.           
  42.         datagramSocket.send(packet2);  
  43.           
  44.         datagramSocket.close();  
  45.           
  46.           
  47.     }  
  48.   
  49. }  

 

 

 

二、客户端

 

Java代码  收藏代码
  1. package com.network;  
  2.   
  3. import java.net.DatagramPacket;  
  4. import java.net.DatagramSocket;  
  5. import java.net.InetAddress;  
  6.   
  7. public class UDPClient  
  8. {  
  9.     public static void main(String[] args) throws Exception  
  10.     {  
  11.         DatagramSocket datagramSocket = new DatagramSocket();  
  12.           
  13.         String content = "hello world!";  
  14.           
  15.         byte[] buffer = content.getBytes();  
  16.           
  17.         InetAddress address = InetAddress.getByName("localhost");  
  18.           
  19.         DatagramPacket packet = new DatagramPacket(buffer,buffer.length,address,5678);  
  20.           
  21.         datagramSocket.send(packet);  
  22.           
  23.         byte[] b = new byte[100];  
  24.           
  25.         DatagramPacket packet2 = new DatagramPacket(b,100);  
  26.           
  27.         datagramSocket.receive(packet2);  
  28.           
  29.         byte[] b2 = packet2.getData();  
  30.           
  31.         int l = packet2.getLength();  
  32.           
  33.         String str = new String(b2,0,l);  
  34.           
  35.         System.out.println("length of string : " + str);  
  36.           
  37.         datagramSocket.close();  
  38.     }  
  39. }  
posted @ 2012-02-11 13:47 喔、勒勒 阅读(33) 评论(0) 编辑

Java Socket 编程之Socket与ServerSocket的区别(转)

1.1 ServerSocket类
   
创建一个ServerSocket类,同时在运行该语句的计算机的指定端口处建立一个监听服务,如:
    ServerSocket MyListener=new ServerSocket(600);
    这里指定提供监听服务的端口是600,一台计算机可以同时提供多个服务,这些不同的服务之间通过端口号来区别,不同的端口号上提供不同的服务。为了随时监听可能的Client请求,执行如下的语句:
    Socket LinkSocket=MyListener.accept();
    该语句调用了ServerSocket对象的accept()方法,这个方法的执行将使Server端的程序处于等待状态,程序将一直阻塞直到捕捉到一个来自Client端的请求,并返回一个用于与该Client通信的Socket对象Link-Socket。此后Server程序只要向这个Socket对象读写数据,就可以实现向远端的Client读写数据。结束监听时,关闭ServerSocket对象:
    Mylistener.close();
1.2 Socket类
    当Client程序需要从Server端获取信息及其他服务时,应创建一个Socket对象:
    Socket MySocket=new Socket(“ServerComputerName”,600);
    Socket类的构造函数有两个参数,第一个参数是欲连接到的Server计算机的主机地址,第二个参数是该Server机上提供服务的端口号。
    Socket对象建立成功之后,就可以在Client和Server之间建立一个连接,并通过这个连接在两个端点之间传递数据。利用Socket类的方法getOutputStream()和getInputStream()分别获得向Socket读写数据的输入/输出流,最后将从Server端读取的数据重新返还到Server端。
    当Server和Client端的通信结束时,可以调用Socket类的close()方法关闭Socket,拆除连接。

ServerSocket 一般仅用于设置端口号和监听,真正进行通信的是服务器端的Socket与客户端的Socket,在ServerSocket 进行accept之后,就将主动权转让了。

1. 服务器端程序设计
    在服务器端,利用ServerSocket类的构造函数ServerSocket(int port)创建一个ServerSocket类的对象,port参数传递端口,这个端口就是服务器监听连接请求的端口,如果在这时出现错误将抛出IOException异常对象,否则将创建ServerSocket对象并开始准备接收连接请求。
    服务程序从调用ServerSocket的accept()方法开始,直到连接建立。在建立连接后,accept()返回一个最近创建的Socket对象,该Socket对象绑定了客户程序的IP地址或端口号。
2.客户端程序设计
    当客户程序需要与服务器程序通信时,需在客户机创建一个Socket对象。Socket类有构造函数Socket(InetAddress addr,int port)和Socket(String host,intport),两个构造函数都创建了一个基于Socket的连接服务器端流套接字的流套接字。对于第一个InetAd-dress子类对象通过addr参数获得服务器主机的IP地址,对于第二个函数host参数包被分配到InetAddress对象中,如果没有IP地址与host参数相一致,那么将抛出UnknownHostException异常对象。两个函数都通过参数port获得服务器的端口号。假设已经建立连接了,网络API将在客户端基于Socket的流套接字中捆绑客户程序的IP地址和任意一个端口号,否则两个函数都会抛出一个IOException对象。
    如果创建了一个Socket对象,那么它可通过get-InputStream()方法从服务程序获得输入流读传送来的信息,也可通过调用getOutputStream()方法获得输出流来发送消息。在读写活动完成之后,客户程序调用close()方法关闭流和流套接字。

附小程序加以说明:

服务器端代码:

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

 

public class Myserver {

//建立ServerSocket,并设置其端口号
    private ServerSocket ss;
  
    public static final int port=8962;
   
    public Myserver(){
   
    try{
   
    ss=new ServerSocket(port);
   
    }catch(IOException e){
   
    e.printStackTrace();
    }
   
    }
    public void setConnection() throws IOException{
   //建立服务器端的Socket
    Socket s;
    OutputStream os;
    try{ //ServerSocke.accept()t返回一个Socket对象

    s=ss.accept();
    os=s.getOutputStream();
    os.write("hello".getBytes());
    os.close();
    s.close();
    }catch(IOException e){
   
    e.printStackTrace();
    }
   
    }

    public static void main(String[] args) throws IOException {
   
    Myserver ms=new Myserver();
    ms.setConnection();
  
}

}

客户端代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

 

public class Myclient {
      public static final String IP="172.16.221.134";
      public static final int port=8962;
      private Socket s;

      public Myclient() throws IOException{
try{
   s=new Socket(IP,port);

}catch(IOException e){
  
   e.printStackTrace();
}
      }
     
      public void setConnection()throws IOException{
      
       InputStream is;
      
    try{
    is=s.getInputStream();
    BufferedReader br=new BufferedReader(new InputStreamReader(is));
   
    System.out.println(br.readLine());
   
    }catch(IOException e){
   
    e.printStackTrace();
    }  
      
     
      }
public static void main(String args[]) throws IOException{
  
   Myclient mc=new Myclient();
   mc.setConnection();
  
}
}

posted @ 2012-02-11 13:26 喔、勒勒 阅读(90) 评论(0) 编辑
  

公告

统计