java.util.DatagramSocket接收和发送udp数据报
java.util.DatagramPacket表示UDP数据报
//发送数据
public void send(DatagramPacket p) throws IOException
//接收数据
public synchronized void receive(DatagramPacket p) throws IOException
---------------------------客户端----------------------------------
/**
* udp客户端
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-24
*
*/
public class EchoClient {
// udp服务器地址
private String remoteHost = "localhost";
private int remotePort = 8000;
private DatagramSocket socket;
/**
* 构造器
*
* @throws SocketException
*/
public EchoClient() throws SocketException {
socket = new DatagramSocket();
}
public void talk() {
try {
InetAddress remoteIP = InetAddress.getByName
(remoteHost);
BufferedReader localReader = new
BufferedReader(new InputStreamReader(System.in));
String msg = null;
while ((msg = localReader.readLine()) !=
null) {
byte[] outputData = msg.getBytes();
DatagramPacket outPacket = new
DatagramPacket(outputData, outputData.length, remoteIP, remotePort);
socket.send(outPacket);// 向服端发送
数据
DatagramPacket inputPacket = new
DatagramPacket(new byte[512], 512);
socket.receive(inputPacket);
System.out.println(new String
(inputPacket.getData(), 0, inputPacket.getLength()));
if (msg.equals("bye")) {
break;
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
socket.close();
}
}
/**
* @param args
* @throws SocketException
*/
public static void main(String[] args) throws SocketException
{
new EchoClient().talk();
}
}
------------------------------服务端-----------------------------
/**
* udp服务端
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-24
*
*/
public class EchoServer {
private int port = 8000;
private DatagramSocket socket;
/**
* 构造器
*
* @throws SocketException
*/
public EchoServer() throws SocketException {
socket = new DatagramSocket();
System.out.println("server is started!");
}
public String echo(String msg) {
return "echo" + msg;
}
public void serviced() {
while (true) {
try {
// 接收来自任意一个客户端的数据报
DatagramPacket packet = new
DatagramPacket(new byte[512], 512);
socket.receive(packet);
String msg = new String
(packet.getData(), packet.getLength());
System.out.println(packet.getAddress
() + ":" + packet.getPort() + ">" + msg);
// 给客户端一个回复
packet.setData(echo(msg).getBytes());
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @param args
* @throws SocketException
*/
public static void main(String[] args) throws SocketException
{
new EchoServer().serviced();
}
}
datagramPacket类
构造方法分为:
接收数据的:
public DatagramPacket(byte buf[],//要发送的数据
int length)//要发送的字节数
public DatagramPacket(byte buf[],//要发送的数据
int offset,//要发送的数据在data中的位置
int length)//要发送的字节数
发送数据的:
public DatagramPacket(byte buf[], //要发送的数据
int offset,//要发送的数据在data中的位置
int length,//要发送的字节数
InetAddress address,//目的地址
int port)//目的端口号
public DatagramPacket(byte buf[], int offset, int length,
SocketAddress address) throws
SocketException
public DatagramPacket(byte buf[], int length,
InetAddress address, int port)
public DatagramPacket(byte buf[], int length,
SocketAddress address) throws
SocketException
------------------数据报的大小(指的是数据部分)----------------
ipv4数据报的最大长度为65507字节
ipv6数据的最大长度为65536字节
原则上不大于8k
udp头包括: ip头 udp头和数据
----------------------读取和设置DatagramentPacket------------------
属性:
byte[] buf; //数据缓冲区
int offset; //数据报在缓冲区的位置
int length; //数据报长度
int bufLength;
InetAddress address; //数据报的目标地址
int port; //UDP端口
可以通过get/set方法获取和设置属性
-----------------------数据格式的转换-------------------
/**
* long型数组转换为字节数组
*
* @param data
* @return
* @throws IOException
*/
public static byte[] longToByte(long[] data) throws
IOException {
ByteArrayOutputStream bos = new
ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
for (int i = 0; i < data.length; i++) {
dos.writeLong(data[i]);
}
dos.close();
return bos.toByteArray();
}
/**
* 字节数组转换为long型数组
*
* @param data
* @return
* @throws IOException
*/
public long[] byteToLong(byte[] data) throws IOException {
long[] result = new long[data.length / 8];
ByteArrayInputStream bis = new ByteArrayInputStream
(data);
DataInputStream dis = new DataInputStream(bis);
for (int i = 0; i < data.length; i++) {
result[i] = dis.readLong();
}
return result;
}
---------------------重用DatagramPacket------------------------
/**
* datagramPacket重用
*
* 用来多次发送或接收数据
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-24
*
*/
public class DatagramTester {
private int port = 8000;
private DatagramSocket sendSocket;
private DatagramSocket receiveSocket;
private static final int MAX_LENGTH = 3584;
/**
* 构造器
*
* @throws SocketException
*/
public DatagramTester() throws SocketException {
sendSocket = new DatagramSocket();
receiveSocket = new DatagramSocket(port);
// 开启收发线程
receiver.start();
sender.start();
}
/**
* long型数组转换为字节数组
*
* @param data
* @return
* @throws IOException
*/
public static byte[] longToByte(long[] data) throws
IOException {
ByteArrayOutputStream bos = new
ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
for (int i = 0; i < data.length; i++) {
dos.writeLong(data[i]);
}
dos.close();
return bos.toByteArray();
}
/**
* 字节数组转换为long型数组
*
* @param data
* @return
* @throws IOException
*/
public long[] byteToLong(byte[] data) throws IOException {
long[] result = new long[data.length / 8];
ByteArrayInputStream bis = new ByteArrayInputStream
(data);
DataInputStream dis = new DataInputStream(bis);
for (int i = 0; i < data.length; i++) {
result[i] = dis.readLong();
}
return result;
}
/**
* 发送数据
*
* @param data
* @throws IOException
*/
public void send(byte[] data) throws IOException {
DatagramPacket packet = new DatagramPacket(data, 0,
512, InetAddress.getByName("localhost"), port);
// 已发送的字节数
int bytesSent = 0;
// 发送次数
int count = 0;
while (bytesSent < data.length) {
sendSocket.send(packet);
System.out.println("<sendSocket>第" + (+
+count) + "次,发送了" + packet.getLength() + "个字节");
// 记当发送字节数
bytesSent += packet.getLength();
// 未发送字节
int remain = data.length - bytesSent;
// 记算下次发送数据的长度
int length = (remain > 512) ? 512 : remain;
// 改变socket属性
packet.setData(data, bytesSent, length);
}
}
/**
* 接收数据
*
* @return
* @throws IOException
*/
public byte[] receive() throws IOException {
byte[] data = new byte[MAX_LENGTH];
// 数据包
DatagramPacket packet = new DatagramPacket(data, 0,
MAX_LENGTH);
// 已接收的字节数
int bytesReceived = 0;
// 接收次数
int count = 0;
// 开始时间
long beginTime = System.currentTimeMillis();
// 如果接收完全部数据,或是超过了5分钟,就结束
while (bytesReceived < data.length &&
((System.currentTimeMillis() - beginTime) < 5000 * 5)) {
receiveSocket.receive(packet);
System.out.println("<ReceiveSoket>第" + (+
+count) + "次接收到" + packet.getLength() + "个字节");
// 记录已接收的字节数
bytesReceived += packet.getLength();
// 修改packet数据包格式
packet.setData(data, bytesReceived,
MAX_LENGTH - bytesReceived);
}
return data;
}
/* 发送线程 */
public Thread sender = new Thread() {
public void run() {
long[] longArray = new long[MAX_LENGTH];
for (int i = 0; i < longArray.length; i++) {
longArray[i] = i + 1;
}
try {
send(longToByte(longArray));
} catch (IOException e) {
e.printStackTrace();
}
};
};
/**
* 接收者线程
*/
public Thread receiver = new Thread() {
public void run() {
try {
long[] longArray = byteToLong
(receive());
// 打印接收到的数据
for (int i = 0; i < longArray.length;
i++) {
if (i % 100 == 0) {
System.out.println();
}
}
} catch (IOException e) {
e.printStackTrace();
}
};
};
@SuppressWarnings("unused")
public static void main(String[] args) throws SocketException
{
DatagramTester tester = new DatagramTester();
}
}
------------------------DatagramSocket-------------------
收发数据报
构造器有以下几种格式:
DatagramSocket() //与匿名端口绑定
DatagramSocket(int port)
DatagramSocket(DatagramSocketImpl impl)
DatagramSocket(SocketAddress bindaddr) //指定ip和端口号
DatagramSocket(int port, InetAddress laddr)//同上
常用方法
getLocalAddress()
getRemoteSocketAddress()
getLocalSocketAddress()
getLocalPort()
接收和发送数据报
//发送
public void send(DatagramPacket p) throws IOException
public synchronized void receive(DatagramPacket p) throws IOException
-----------------------管理连接------------------------------
//只与指定的远程主机和UDP端口号收发数据
public void connect(InetAddress address, int port)
//终止当前连接
public void disconnect()
//只有建立连接时才会返回,远程端口号
getPort()
//同上,返回远程ip
getInetAddress()
//同上
getRemoteSocketAddress()
------------------------关闭DatagramSocket---------------
close()
SocketOptions的几个选项
public final static int SO_TIMEOUT = 0x1006;//等待超时时间
public final static int SO_RCVBUF = 0x1002;//接收数据缓冲区的大小
public final static int SO_SNDBUF = 0x1001;//发送数据缓冲区的大小
是否允许重用datagramSocket所绑定的地址
public final static int SO_REUSEADDR = 0x04;
//是否允许对网络广播地址收发数据报
public final static int SO_BROADCAST = 0x0020;
//可以使用以下方法对选项进行设置
receiveSocket.setSoTimeout(timeout);
//源代码中是通过以下式实现
setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout))
其他同理
---------------------ip服务类型选项-------------------
//设置服务类型
public synchronized void setTrafficClass(int tc) throws
SocketException
//读取服务类型
public synchronized void setTrafficClass(int tc) throws
SocketException
四种服务类型
0x02(二进制倒数第二位为1) 成本低
0x04(倒数第三位为1) 高可靠性
0x08(倒数第四位为1) 高吞吐量
0x10(倒数第五位为1) 最小延迟
----------------------DatagramChannel类-----------------------
非阻塞方式发送和接收数据包,是selectableChannel的子类,服务器通过单个
线程和多个客户通信
//创建datagramChannel,示例代码如下:
DatagramChannel channel = DatagramChannel.open();
DatagramSocket socket = channel.socket();
SocketAddress address = new InetSocketAddress(8000);
// 绑定一个本地地址
socket.bind(address);
------------------------管理连接---------------------------------
一般 不对datagramChannel进行连接
-----------------------收发数据报---------------------------------
//发送数据报
channel.send(src, target)
//把缓冲区的位置重设为零
src.rewind();
注:send方法不会分为多个数据报发送,要么全发,要么一个不发
//接收数据报
public abstract SocketAddress receive(ByteBuffer dst) throws
IOException
示例代码如下:
/**
* 发送数据
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-25
*
*/
public class SendChannel {
/**
* @param args
* @throws IOException
* @throws InterruptedException
*/
public static void main(String[] args) throws IOException,
InterruptedException {
DatagramChannel channel = DatagramChannel.open();
DatagramSocket socket = channel.socket();
SocketAddress localAddress = new InetSocketAddress
(7000);
SocketAddress remoteAddress = new InetSocketAddress
(InetAddress.getByName("localhost"), 8000);
// 绑定本地地址
socket.bind(localAddress);
while (true) {
ByteBuffer buffer = ByteBuffer.allocate
(1024);
buffer.clear();
System.out.println("缓冲区的剩余字节为:" +
buffer.remaining());
int n = channel.send(buffer, remoteAddress);
System.out.println("发送的字节数为:" + n);
TimeUnit.MICROSECONDS.sleep(500);
}
}
}
/**
*
* 接收数据报
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-25
*
*/
public class ReceiveChannel {
/**
* @param args
* @throws IOException
* @throws InterruptedException
*/
public static void main(String[] args) throws IOException,
InterruptedException {
//缓冲字节大小
final int ENOUGH_SIZE = 1024;
final int SMALL_SIZE = 4;
// 是否是阻塞模式
boolean isBlocked = true;
int size = ENOUGH_SIZE;
if (args.length > 0) {
// 读取命令行参数
int opt = Integer.parseInt(args[0]);
switch (opt) {
case 1:
isBlocked = true;
size = ENOUGH_SIZE;
break;
case 2:
isBlocked = true;
size = SMALL_SIZE;
break;
case 3:
isBlocked = false;
size = ENOUGH_SIZE;
break;
case 4:
isBlocked = false;
size = SMALL_SIZE;
break;
}
}
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(isBlocked);
// 用于接收数据的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(size);
DatagramSocket socket = channel.socket();
SocketAddress localAddress = new InetSocketAddress
(8000);
socket.bind(localAddress);
while (true) {
System.out.println("开始接收数据");
SocketAddress remoteAddress =
channel.receive(buffer);
if (null == remoteAddress) {
System.out.println("没有接收到数据
报");
} else {
buffer.flip();
System.out.println("接收到的数据大小
为:" + buffer.remaining());
}
,TimeUnit.MICROSECONDS.sleep(500);
}
}
}
--------------------------read/write方式收发数据包----------------
write发送数据报,有以下几种形式
//依次发送bytebuffer中每一个byteBuffer的数据
public abstract int write(ByteBuffer src) throws IOException
public final long write(ByteBuffer[] srcs) throws IOException
public abstract long write(ByteBuffer[] srcs,//
int offset,//
int length)throws IOException;//指定buffer的个数
write()与send()的区别:
write()需要先调用connect()与远程进立连接
非阻塞模式下,write()不能保证所剩作数据作为一个数据报发送
要想发送所有剩余数据,可以采用以下方法
while(buffer.hasRemaining()&&channel.write(buffer)!=1){
}
read()接收数据报
//返回实际接收数据的字节数,只接收一个数据报,保存在byteBufferkh
public abstract int read(ByteBuffer dst) throws IOException;
public final long read(ByteBuffer[] dsts) throws IOException
public abstract long read(ByteBuffer[] dsts, int offset, int
length)
throws IOException;
read()和receive()一样,如果缓冲区小接收数据,多余的数据将被丢弃
------------------------------组播--------------------------------
网络数据传播的三种方式:
单播:
广播:
组播:
java.net.MulticastSocket具有组播的功能,是datagramSocket的子类
如果要接收组播数据报,需要建立MulticastSocket,添加到组播组
发送组播数据报不用添加到组播组,需要先调用setTimeToLive()方法
//构造器
//绑定匿名接口,(只发送)
public MulticastSocket() throws IOException
//以下两种可用于接收
public MulticastSocket(int port) throws IOException
//如果参数设为空,后期需要使用bind()重新绑定
public MulticastSocket(SocketAddress bindaddr) throws IOException
与组播组通信有四种方法:
加入组播组
public void joinGroup(InetAddress mcastaddr) throws IOException
public void joinGroup(SocketAddress mcastaddr,//指定组播地址
NetworkInterface netIf)//指定网络接口
throws IOException
向组中成员发送数据报
public void send(DatagramPacket p, byte ttl)throws IOException
接收组播数据报
receive()//接收和发送数据报,象是调用的datagramSocket中的方法
离开组播组
public void leaveGroup(InetAddress mcastaddr) throws IOException
public void leaveGroup(SocketAddress mcastaddr, NetworkInterface
netIf)throws IOException
组播地址位于224.0.0.0-239.255.255.255
multicastSocket的属性
//读取和设置网络接口
public InetAddress getInterface() throws SocketException
public void setInterface(InetAddress inf) throws SocketException
//networkInterface有唯一的域名
public NetworkInterface getNetworkInterface() throws SocketException
public void setNetworkInterface(NetworkInterface netIf)throws
SocketException
//读取和设置ttl属性
public int getTimeToLive() throws IOException
//ttl属性决定了数据报允放通过的路由器的数目
public void setTimeToLive(int ttl) throws IOException
//读取和设置组播数据报回送模式
public boolean getLoopbackMode() throws SocketException
//是否接收自身发送的数据报,true为不接收
public void setLoopbackMode(boolean disable) throws SocketException
组播socket的范例
/**
* 组播发送
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-26
*
*/
public class MutlcastSocketSender {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 组播地址及端口
InetAddress group = InetAddress.getByName
("192.168.255");
int port = 4000;
MulticastSocket msSocket = null;
try {
msSocket = new MulticastSocket(port);
msSocket.joinGroup(group);
while (true) {
String message = "hello" + new Date
();
byte[] buffer = message.getBytes();
DatagramPacket packet = new
DatagramPacket(buffer, buffer.length, group, port);
// 发送组播数据报
msSocket.send(packet);
System.out.println("发送数据报给" +
group + ":" + port);
TimeUnit.MICROSECONDS.sleep(1000);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (null != msSocket) {
try {
msSocket.leaveGroup(group);
msSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
-------------------------------------------------
java.util.DatagramPacket表示UDP数据报
//发送数据
public void send(DatagramPacket p) throws IOException
//接收数据
public synchronized void receive(DatagramPacket p) throws IOException
---------------------------客户端----------------------------------
/**
* udp客户端
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-24
*
*/
public class EchoClient {
// udp服务器地址
private String remoteHost = "localhost";
private int remotePort = 8000;
private DatagramSocket socket;
/**
* 构造器
*
* @throws SocketException
*/
public EchoClient() throws SocketException {
socket = new DatagramSocket();
}
public void talk() {
try {
InetAddress remoteIP = InetAddress.getByName
(remoteHost);
BufferedReader localReader = new
BufferedReader(new InputStreamReader(System.in));
String msg = null;
while ((msg = localReader.readLine()) !=
null) {
byte[] outputData = msg.getBytes();
DatagramPacket outPacket = new
DatagramPacket(outputData, outputData.length, remoteIP, remotePort);
socket.send(outPacket);// 向服端发送
数据
DatagramPacket inputPacket = new
DatagramPacket(new byte[512], 512);
socket.receive(inputPacket);
System.out.println(new String
(inputPacket.getData(), 0, inputPacket.getLength()));
if (msg.equals("bye")) {
break;
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
socket.close();
}
}
/**
* @param args
* @throws SocketException
*/
public static void main(String[] args) throws SocketException
{
new EchoClient().talk();
}
}
------------------------------服务端-----------------------------
/**
* udp服务端
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-24
*
*/
public class EchoServer {
private int port = 8000;
private DatagramSocket socket;
/**
* 构造器
*
* @throws SocketException
*/
public EchoServer() throws SocketException {
socket = new DatagramSocket();
System.out.println("server is started!");
}
public String echo(String msg) {
return "echo" + msg;
}
public void serviced() {
while (true) {
try {
// 接收来自任意一个客户端的数据报
DatagramPacket packet = new
DatagramPacket(new byte[512], 512);
socket.receive(packet);
String msg = new String
(packet.getData(), packet.getLength());
System.out.println(packet.getAddress
() + ":" + packet.getPort() + ">" + msg);
// 给客户端一个回复
packet.setData(echo(msg).getBytes());
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @param args
* @throws SocketException
*/
public static void main(String[] args) throws SocketException
{
new EchoServer().serviced();
}
}
datagramPacket类
构造方法分为:
接收数据的:
public DatagramPacket(byte buf[],//要发送的数据
int length)//要发送的字节数
public DatagramPacket(byte buf[],//要发送的数据
int offset,//要发送的数据在data中的位置
int length)//要发送的字节数
发送数据的:
public DatagramPacket(byte buf[], //要发送的数据
int offset,//要发送的数据在data中的位置
int length,//要发送的字节数
InetAddress address,//目的地址
int port)//目的端口号
public DatagramPacket(byte buf[], int offset, int length,
SocketAddress address) throws
SocketException
public DatagramPacket(byte buf[], int length,
InetAddress address, int port)
public DatagramPacket(byte buf[], int length,
SocketAddress address) throws
SocketException
------------------数据报的大小(指的是数据部分)----------------
ipv4数据报的最大长度为65507字节
ipv6数据的最大长度为65536字节
原则上不大于8k
udp头包括: ip头 udp头和数据
----------------------读取和设置DatagramentPacket------------------
属性:
byte[] buf; //数据缓冲区
int offset; //数据报在缓冲区的位置
int length; //数据报长度
int bufLength;
InetAddress address; //数据报的目标地址
int port; //UDP端口
可以通过get/set方法获取和设置属性
-----------------------数据格式的转换-------------------
/**
* long型数组转换为字节数组
*
* @param data
* @return
* @throws IOException
*/
public static byte[] longToByte(long[] data) throws
IOException {
ByteArrayOutputStream bos = new
ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
for (int i = 0; i < data.length; i++) {
dos.writeLong(data[i]);
}
dos.close();
return bos.toByteArray();
}
/**
* 字节数组转换为long型数组
*
* @param data
* @return
* @throws IOException
*/
public long[] byteToLong(byte[] data) throws IOException {
long[] result = new long[data.length / 8];
ByteArrayInputStream bis = new ByteArrayInputStream
(data);
DataInputStream dis = new DataInputStream(bis);
for (int i = 0; i < data.length; i++) {
result[i] = dis.readLong();
}
return result;
}
---------------------重用DatagramPacket------------------------
/**
* datagramPacket重用
*
* 用来多次发送或接收数据
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-24
*
*/
public class DatagramTester {
private int port = 8000;
private DatagramSocket sendSocket;
private DatagramSocket receiveSocket;
private static final int MAX_LENGTH = 3584;
/**
* 构造器
*
* @throws SocketException
*/
public DatagramTester() throws SocketException {
sendSocket = new DatagramSocket();
receiveSocket = new DatagramSocket(port);
// 开启收发线程
receiver.start();
sender.start();
}
/**
* long型数组转换为字节数组
*
* @param data
* @return
* @throws IOException
*/
public static byte[] longToByte(long[] data) throws
IOException {
ByteArrayOutputStream bos = new
ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
for (int i = 0; i < data.length; i++) {
dos.writeLong(data[i]);
}
dos.close();
return bos.toByteArray();
}
/**
* 字节数组转换为long型数组
*
* @param data
* @return
* @throws IOException
*/
public long[] byteToLong(byte[] data) throws IOException {
long[] result = new long[data.length / 8];
ByteArrayInputStream bis = new ByteArrayInputStream
(data);
DataInputStream dis = new DataInputStream(bis);
for (int i = 0; i < data.length; i++) {
result[i] = dis.readLong();
}
return result;
}
/**
* 发送数据
*
* @param data
* @throws IOException
*/
public void send(byte[] data) throws IOException {
DatagramPacket packet = new DatagramPacket(data, 0,
512, InetAddress.getByName("localhost"), port);
// 已发送的字节数
int bytesSent = 0;
// 发送次数
int count = 0;
while (bytesSent < data.length) {
sendSocket.send(packet);
System.out.println("<sendSocket>第" + (+
+count) + "次,发送了" + packet.getLength() + "个字节");
// 记当发送字节数
bytesSent += packet.getLength();
// 未发送字节
int remain = data.length - bytesSent;
// 记算下次发送数据的长度
int length = (remain > 512) ? 512 : remain;
// 改变socket属性
packet.setData(data, bytesSent, length);
}
}
/**
* 接收数据
*
* @return
* @throws IOException
*/
public byte[] receive() throws IOException {
byte[] data = new byte[MAX_LENGTH];
// 数据包
DatagramPacket packet = new DatagramPacket(data, 0,
MAX_LENGTH);
// 已接收的字节数
int bytesReceived = 0;
// 接收次数
int count = 0;
// 开始时间
long beginTime = System.currentTimeMillis();
// 如果接收完全部数据,或是超过了5分钟,就结束
while (bytesReceived < data.length &&
((System.currentTimeMillis() - beginTime) < 5000 * 5)) {
receiveSocket.receive(packet);
System.out.println("<ReceiveSoket>第" + (+
+count) + "次接收到" + packet.getLength() + "个字节");
// 记录已接收的字节数
bytesReceived += packet.getLength();
// 修改packet数据包格式
packet.setData(data, bytesReceived,
MAX_LENGTH - bytesReceived);
}
return data;
}
/* 发送线程 */
public Thread sender = new Thread() {
public void run() {
long[] longArray = new long[MAX_LENGTH];
for (int i = 0; i < longArray.length; i++) {
longArray[i] = i + 1;
}
try {
send(longToByte(longArray));
} catch (IOException e) {
e.printStackTrace();
}
};
};
/**
* 接收者线程
*/
public Thread receiver = new Thread() {
public void run() {
try {
long[] longArray = byteToLong
(receive());
// 打印接收到的数据
for (int i = 0; i < longArray.length;
i++) {
if (i % 100 == 0) {
System.out.println();
}
}
} catch (IOException e) {
e.printStackTrace();
}
};
};
@SuppressWarnings("unused")
public static void main(String[] args) throws SocketException
{
DatagramTester tester = new DatagramTester();
}
}
------------------------DatagramSocket-------------------
收发数据报
构造器有以下几种格式:
DatagramSocket() //与匿名端口绑定
DatagramSocket(int port)
DatagramSocket(DatagramSocketImpl impl)
DatagramSocket(SocketAddress bindaddr) //指定ip和端口号
DatagramSocket(int port, InetAddress laddr)//同上
常用方法
getLocalAddress()
getRemoteSocketAddress()
getLocalSocketAddress()
getLocalPort()
接收和发送数据报
//发送
public void send(DatagramPacket p) throws IOException
public synchronized void receive(DatagramPacket p) throws IOException
-----------------------管理连接------------------------------
//只与指定的远程主机和UDP端口号收发数据
public void connect(InetAddress address, int port)
//终止当前连接
public void disconnect()
//只有建立连接时才会返回,远程端口号
getPort()
//同上,返回远程ip
getInetAddress()
//同上
getRemoteSocketAddress()
------------------------关闭DatagramSocket---------------
close()
SocketOptions的几个选项
public final static int SO_TIMEOUT = 0x1006;//等待超时时间
public final static int SO_RCVBUF = 0x1002;//接收数据缓冲区的大小
public final static int SO_SNDBUF = 0x1001;//发送数据缓冲区的大小
是否允许重用datagramSocket所绑定的地址
public final static int SO_REUSEADDR = 0x04;
//是否允许对网络广播地址收发数据报
public final static int SO_BROADCAST = 0x0020;
//可以使用以下方法对选项进行设置
receiveSocket.setSoTimeout(timeout);
//源代码中是通过以下式实现
setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout))
其他同理
---------------------ip服务类型选项-------------------
//设置服务类型
public synchronized void setTrafficClass(int tc) throws
SocketException
//读取服务类型
public synchronized void setTrafficClass(int tc) throws
SocketException
四种服务类型
0x02(二进制倒数第二位为1) 成本低
0x04(倒数第三位为1) 高可靠性
0x08(倒数第四位为1) 高吞吐量
0x10(倒数第五位为1) 最小延迟
----------------------DatagramChannel类-----------------------
非阻塞方式发送和接收数据包,是selectableChannel的子类,服务器通过单个
线程和多个客户通信
//创建datagramChannel,示例代码如下:
DatagramChannel channel = DatagramChannel.open();
DatagramSocket socket = channel.socket();
SocketAddress address = new InetSocketAddress(8000);
// 绑定一个本地地址
socket.bind(address);
------------------------管理连接---------------------------------
一般 不对datagramChannel进行连接
-----------------------收发数据报---------------------------------
//发送数据报
channel.send(src, target)
//把缓冲区的位置重设为零
src.rewind();
注:send方法不会分为多个数据报发送,要么全发,要么一个不发
//接收数据报
public abstract SocketAddress receive(ByteBuffer dst) throws
IOException
示例代码如下:
/**
* 发送数据
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-25
*
*/
public class SendChannel {
/**
* @param args
* @throws IOException
* @throws InterruptedException
*/
public static void main(String[] args) throws IOException,
InterruptedException {
DatagramChannel channel = DatagramChannel.open();
DatagramSocket socket = channel.socket();
SocketAddress localAddress = new InetSocketAddress
(7000);
SocketAddress remoteAddress = new InetSocketAddress
(InetAddress.getByName("localhost"), 8000);
// 绑定本地地址
socket.bind(localAddress);
while (true) {
ByteBuffer buffer = ByteBuffer.allocate
(1024);
buffer.clear();
System.out.println("缓冲区的剩余字节为:" +
buffer.remaining());
int n = channel.send(buffer, remoteAddress);
System.out.println("发送的字节数为:" + n);
TimeUnit.MICROSECONDS.sleep(500);
}
}
}
/**
*
* 接收数据报
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-25
*
*/
public class ReceiveChannel {
/**
* @param args
* @throws IOException
* @throws InterruptedException
*/
public static void main(String[] args) throws IOException,
InterruptedException {
//缓冲字节大小
final int ENOUGH_SIZE = 1024;
final int SMALL_SIZE = 4;
// 是否是阻塞模式
boolean isBlocked = true;
int size = ENOUGH_SIZE;
if (args.length > 0) {
// 读取命令行参数
int opt = Integer.parseInt(args[0]);
switch (opt) {
case 1:
isBlocked = true;
size = ENOUGH_SIZE;
break;
case 2:
isBlocked = true;
size = SMALL_SIZE;
break;
case 3:
isBlocked = false;
size = ENOUGH_SIZE;
break;
case 4:
isBlocked = false;
size = SMALL_SIZE;
break;
}
}
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(isBlocked);
// 用于接收数据的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(size);
DatagramSocket socket = channel.socket();
SocketAddress localAddress = new InetSocketAddress
(8000);
socket.bind(localAddress);
while (true) {
System.out.println("开始接收数据");
SocketAddress remoteAddress =
channel.receive(buffer);
if (null == remoteAddress) {
System.out.println("没有接收到数据
报");
} else {
buffer.flip();
System.out.println("接收到的数据大小
为:" + buffer.remaining());
}
,TimeUnit.MICROSECONDS.sleep(500);
}
}
}
--------------------------read/write方式收发数据包----------------
write发送数据报,有以下几种形式
//依次发送bytebuffer中每一个byteBuffer的数据
public abstract int write(ByteBuffer src) throws IOException
public final long write(ByteBuffer[] srcs) throws IOException
public abstract long write(ByteBuffer[] srcs,//
int offset,//
int length)throws IOException;//指定buffer的个数
write()与send()的区别:
write()需要先调用connect()与远程进立连接
非阻塞模式下,write()不能保证所剩作数据作为一个数据报发送
要想发送所有剩余数据,可以采用以下方法
while(buffer.hasRemaining()&&channel.write(buffer)!=1){
}
read()接收数据报
//返回实际接收数据的字节数,只接收一个数据报,保存在byteBufferkh
public abstract int read(ByteBuffer dst) throws IOException;
public final long read(ByteBuffer[] dsts) throws IOException
public abstract long read(ByteBuffer[] dsts, int offset, int
length)
throws IOException;
read()和receive()一样,如果缓冲区小接收数据,多余的数据将被丢弃
------------------------------组播--------------------------------
网络数据传播的三种方式:
单播:
广播:
组播:
java.net.MulticastSocket具有组播的功能,是datagramSocket的子类
如果要接收组播数据报,需要建立MulticastSocket,添加到组播组
发送组播数据报不用添加到组播组,需要先调用setTimeToLive()方法
//构造器
//绑定匿名接口,(只发送)
public MulticastSocket() throws IOException
//以下两种可用于接收
public MulticastSocket(int port) throws IOException
//如果参数设为空,后期需要使用bind()重新绑定
public MulticastSocket(SocketAddress bindaddr) throws IOException
与组播组通信有四种方法:
加入组播组
public void joinGroup(InetAddress mcastaddr) throws IOException
public void joinGroup(SocketAddress mcastaddr,//指定组播地址
NetworkInterface netIf)//指定网络接口
throws IOException
向组中成员发送数据报
public void send(DatagramPacket p, byte ttl)throws IOException
接收组播数据报
receive()//接收和发送数据报,象是调用的datagramSocket中的方法
离开组播组
public void leaveGroup(InetAddress mcastaddr) throws IOException
public void leaveGroup(SocketAddress mcastaddr, NetworkInterface
netIf)throws IOException
组播地址位于224.0.0.0-239.255.255.255
multicastSocket的属性
//读取和设置网络接口
public InetAddress getInterface() throws SocketException
public void setInterface(InetAddress inf) throws SocketException
//networkInterface有唯一的域名
public NetworkInterface getNetworkInterface() throws SocketException
public void setNetworkInterface(NetworkInterface netIf)throws
SocketException
//读取和设置ttl属性
public int getTimeToLive() throws IOException
//ttl属性决定了数据报允放通过的路由器的数目
public void setTimeToLive(int ttl) throws IOException
//读取和设置组播数据报回送模式
public boolean getLoopbackMode() throws SocketException
//是否接收自身发送的数据报,true为不接收
public void setLoopbackMode(boolean disable) throws SocketException
组播socket的范例
/**
* 组播发送
*
* @version
*
* @Description:
*
* @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>
*
* @since 2014-6-26
*
*/
public class MutlcastSocketSender {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 组播地址及端口
InetAddress group = InetAddress.getByName
("192.168.255");
int port = 4000;
MulticastSocket msSocket = null;
try {
msSocket = new MulticastSocket(port);
msSocket.joinGroup(group);
while (true) {
String message = "hello" + new Date
();
byte[] buffer = message.getBytes();
DatagramPacket packet = new
DatagramPacket(buffer, buffer.length, group, port);
// 发送组播数据报
msSocket.send(packet);
System.out.println("发送数据报给" +
group + ":" + port);
TimeUnit.MICROSECONDS.sleep(1000);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (null != msSocket) {
try {
msSocket.leaveGroup(group);
msSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
-------------------------------------------------