java udp 点对点_JAVA-UDP辅助TCP实现点对点传输

public class ServerInfo {

private String sn;

private int port;

private String address;

public ServerInfo(int port, String ip, String sn) {

this.port = port;

this.address = ip;

this.sn = sn;

}

public String getSn() {

return sn;

}

public void setSn(String sn) {

this.sn = sn;

}

public int getPort() {

return port;

}

public void setPort(int port) {

this.port = port;

}

public String getAddress() {

return address;

}

public void setAddress(String address) {

this.address = address;

}

@Override

public String toString() {

return "ServerInfo{" +

"sn='" + sn + '\'' +

", port=" + port +

", address='" + address + '\'' +

'}';

}

}

客户端:

public class Client {

public static void main(String[] args) {

ServerInfo info = ClientSearcher.searchServer(10000);

System.out.println("Server:" + info);

}

}

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.nio.ByteBuffer;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.TimeUnit;

public class ClientSearcher {

private static final int LISTEN_PORT = UDPConstants.PORT_CLIENT_RESPONSE;

public static ServerInfo searchServer(int timeout) {

System.out.println("UDPSearcher Started.");

// 成功收到回送的栅栏

CountDownLatch receiveLatch = new CountDownLatch(1);

Listener listener = null;

try {

listener = listen(receiveLatch);

sendBroadcast();

receiveLatch.await(timeout, TimeUnit.MILLISECONDS);

} catch (Exception e) {

e.printStackTrace();

}

// 完成

System.out.println("UDPSearcher Finished.");

if (listener == null) {

return null;

}

List devices = listener.getServerAndClose();

if (devices.size() > 0) {

return devices.get(0);

}

return null;

}

private static Listener listen(CountDownLatch receiveLatch) throws InterruptedException {

System.out.println("UDPSearcher start listen.");

CountDownLatch startDownLatch = new CountDownLatch(1);

Listener listener = new Listener(LISTEN_PORT, startDownLatch, receiveLatch);

listener.start();

startDownLatch.await();

return listener;

}

private static void sendBroadcast() throws IOException {

System.out.println("UDPSearcher sendBroadcast started.");

// 作为搜索方,让系统自动分配端口

DatagramSocket ds = new DatagramSocket();

// 构建一份请求数据

ByteBuffer byteBuffer = ByteBuffer.allocate(128);

// 头部

byteBuffer.put(UDPConstants.HEADER);

// CMD命名

byteBuffer.putShort((short) 1);

// 回送端口信息

byteBuffer.putInt(LISTEN_PORT);

// 直接构建packet

DatagramPacket requestPacket = new DatagramPacket(byteBuffer.array(),

byteBuffer.position() + 1);

// 广播地址

requestPacket.setAddress(InetAddress.getByName("255.255.255.255"));

// 设置服务器端口

requestPacket.setPort(UDPConstants.PORT_SERVER);

// 发送

ds.send(requestPacket);

ds.close();

// 完成

System.out.println("UDPSearcher sendBroadcast finished.");

}

private static class Listener extends Thread {

private final int listenPort;

private final CountDownLatch startDownLatch;

private final CountDownLatch receiveDownLatch;

private final List serverInfoList = new ArrayList<>();

private final byte[] buffer = new byte[128];

private final int minLen = UDPConstants.HEADER.length + 2 + 4;

private boolean done = false;

private DatagramSocket ds = null;

private Listener(int listenPort, CountDownLatch startDownLatch, CountDownLatch receiveDownLatch) {

super();

this.listenPort = listenPort;

this.startDownLatch = startDownLatch;

this.receiveDownLatch = receiveDownLatch;

}

@Override

public void run() {

super.run();

// 通知已启动

startDownLatch.countDown();

try {

// 监听回送端口

ds = new DatagramSocket(listenPort);

// 构建接收实体

DatagramPacket receivePack = new DatagramPacket(buffer, buffer.length);

while (!done) {

// 接收

ds.receive(receivePack);

// 打印接收到的信息与发送者的信息

// 发送者的IP地址

String ip = receivePack.getAddress().getHostAddress();

int port = receivePack.getPort();

int dataLen = receivePack.getLength();

byte[] data = receivePack.getData();

boolean isValid = dataLen >= minLen

&& ByteUtils.startsWith(data, UDPConstants.HEADER);

System.out.println("UDPSearcher receive form ip:" + ip

+ "\tport:" + port + "\tdataValid:" + isValid);

if (!isValid) {

// 无效继续

continue;

}

ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, UDPConstants.HEADER.length, dataLen);

final short cmd = byteBuffer.getShort();

final int serverPort = byteBuffer.getInt();

if (cmd != 2 || serverPort <= 0) {

System.out.println("UDPSearcher receive cmd:" + cmd + "\tserverPort:" + serverPort);

continue;

}

String sn = new String(buffer, minLen, dataLen - minLen);

ServerInfo info = new ServerInfo(serverPort, ip, sn);

serverInfoList.add(info);

// 成功接收到一份

receiveDownLatch.countDown();

}

} catch (Exception ignored) {

} finally {

close();

}

System.out.println("UDPSearcher listener finished.");

}

private void close() {

if (ds != null) {

ds.close();

ds = null;

}

}

List getServerAndClose() {

done = true;

close();

return serverInfoList;

}

}

}

帮助类:

public class ByteUtils {

/**

* Does this byte array begin with match array content?

*

* @param source Byte array to examine

* @param match Byte array to locate in source

* @return true If the starting bytes are equal

*/

public static boolean startsWith(byte[] source, byte[] match) {

return startsWith(source, 0, match);

}

/**

* Does this byte array begin with match array content?

*

* @param source Byte array to examine

* @param offset An offset into the source array

* @param match Byte array to locate in source

* @return true If the starting bytes are equal

*/

public static boolean startsWith(byte[] source, int offset, byte[] match) {

if (match.length > (source.length - offset)) {

return false;

}

for (int i = 0; i < match.length; i++) {

if (source[offset + i] != match[i]) {

return false;

}

}

return true;

}

/**

* Does the source array equal the match array?

*

* @param source Byte array to examine

* @param match Byte array to locate in source

* @return true If the two arrays are equal

*/

public static boolean equals(byte[] source, byte[] match) {

if (match.length != source.length) {

return false;

}

return startsWith(source, 0, match);

}

/**

* Copies bytes from the source byte array to the destination array

*

* @param source The source array

* @param srcBegin Index of the first source byte to copy

* @param srcEnd Index after the last source byte to copy

* @param destination The destination array

* @param dstBegin The starting offset in the destination array

*/

public static void getBytes(byte[] source, int srcBegin, int srcEnd, byte[] destination,

int dstBegin) {

System.arraycopy(source, srcBegin, destination, dstBegin, srcEnd - srcBegin);

}

/**

* Return a new byte array containing a sub-portion of the source array

*

* @param srcBegin The beginning index (inclusive)

* @param srcEnd The ending index (exclusive)

* @return The new, populated byte array

*/

public static byte[] subbytes(byte[] source, int srcBegin, int srcEnd) {

byte destination[];

destination = new byte[srcEnd - srcBegin];

getBytes(source, srcBegin, srcEnd, destination, 0);

return destination;

}

/**

* Return a new byte array containing a sub-portion of the source array

*

* @param srcBegin The beginning index (inclusive)

* @return The new, populated byte array

*/

public static byte[] subbytes(byte[] source, int srcBegin) {

return subbytes(source, srcBegin, source.length);

}

}

public class TCPConstants {

// 服务器固化UDP接收端口

public static int PORT_SERVER = 30401;

}

public class UDPConstants {

// 公用头部

public static byte[] HEADER = new byte[]{7, 7, 7, 7, 7, 7, 7, 7};

// 服务器固化UDP接收端口

public static int PORT_SERVER=30201;

// 客户端回送端口

public static int PORT_CLIENT_RESPONSE = 30202;

}

import java.io.IOException;

public class Server {

public static void main(String[] args) {

ServerProvider.start(TCPConstants.PORT_SERVER);

try {

System.in.read();

}catch (IOException e) {

e.printStackTrace();

}

ServerProvider.stop();

}

}

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.nio.ByteBuffer;

import java.util.UUID;

public class ServerProvider {

private static Provider PROVIDER_INSTANCE;

static void start(int port) {

stop();

String sn = UUID.randomUUID().toString();

Provider provider = new Provider(sn, port);

provider.start();

PROVIDER_INSTANCE = provider;

}

static void stop() {

if (PROVIDER_INSTANCE != null) {

PROVIDER_INSTANCE.exit();

PROVIDER_INSTANCE = null;

}

}

private static class Provider extends Thread {

private final byte[] sn;

private final int port;

private boolean done = false;

private DatagramSocket ds = null;

// 存储消息的Buffer

final byte[] buffer = new byte[128];

Provider(String sn, int port) {

super();

this.sn = sn.getBytes();

this.port = port;

}

@Override

public void run() {

super.run();

System.out.println("UDPProvider Started.");

try {

// 监听20000 端口

ds = new DatagramSocket(UDPConstants.PORT_SERVER);

// 接收消息的Packet

DatagramPacket receivePack = new DatagramPacket(buffer, buffer.length);

while (!done) {

// 接收

ds.receive(receivePack);

// 打印接收到的信息与发送者的信息

// 发送者的IP地址

String clientIp = receivePack.getAddress().getHostAddress();

int clientPort = receivePack.getPort();

int clientDataLen = receivePack.getLength();

byte[] clientData = receivePack.getData();

boolean isValid = clientDataLen >= (UDPConstants.HEADER.length + 2 + 4)

&& ByteUtils.startsWith(clientData, UDPConstants.HEADER);

System.out.println("ServerProvider receive form ip:" + clientIp

+ "\tport:" + clientPort + "\tdataValid:" + isValid);

if (!isValid) {

// 无效继续

continue;

}

// 解析命令与回送端口

int index = UDPConstants.HEADER.length;

short cmd = (short) ((clientData[index++] << 8) | (clientData[index++] & 0xff));

int responsePort = (((clientData[index++]) << 24) |

((clientData[index++] & 0xff) << 16) |

((clientData[index++] & 0xff) << 8) |

((clientData[index] & 0xff)));

// 判断合法性

if (cmd == 1 && responsePort > 0) {

// 构建一份回送数据

ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);

byteBuffer.put(UDPConstants.HEADER);

byteBuffer.putShort((short) 2);

byteBuffer.putInt(port);

byteBuffer.put(sn);

int len = byteBuffer.position();

// 直接根据发送者构建一份回送信息

DatagramPacket responsePacket = new DatagramPacket(buffer,

len,

receivePack.getAddress(),

responsePort);

ds.send(responsePacket);

System.out.println("ServerProvider response to:" + clientIp + "\tport:" + responsePort + "\tdataLen:" + len);

} else {

System.out.println("ServerProvider receive cmd nonsupport; cmd:" + cmd + "\tport:" + port);

}

}

} catch (Exception ignored) {

} finally {

close();

}

// 完成

System.out.println("UDPProvider Finished.");

}

private void close() {

if (ds != null) {

ds.close();

ds = null;

}

}

/**

* 提供结束

*/

void exit() {

done = true;

close();

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值