刚刚写了一个UDP通信的小程序,遇到几个小问题记录下来备案:
1.客户端异常
客户端的几种异常java已经默认的需要程序员try catch掉了,可是有一种异常java没有默认地帮助程序员考虑,那就是客户端先于服务器端启动,注意,不是服务器端的主机没有开启,而是服务器程序没有启动,这时候我们编写的客户端程序会永久挂起,除非强行关闭。关于这一点,我开始想到使用定时器timer通过三步握手判断,延时3秒,如果还是没有接收到server端发来的欢迎信息则退出程序。可是这种timer方法实践证明并不可行,或者说比较繁琐,因为timer本身会启动一个线程,而DUP的DatagramSocket的receive方法也会启动一个线程,如果两个线程同时在争用一个资源(毫无疑问,肯定是DatagramPacket的一个对象,因为DatagrameSocket会向packet中receive,而timer又要判断packet包中是否有数据),就会出现同步的问题,想解决同步问题也不是没有可能,可以使用syncronize关键字,不过这样一来程序就显得非常繁琐。后来查询SDK文档,发现一个SocketTimeoutException,这样一来就方便多了,代码如下:

try...{
DatagramSocket dsSend = new DatagramSocket();
DatagramSocket dsReceive = new DatagramSocket(4502);
DatagramPacket dpReceive = new DatagramPacket(buf, 100);

DatagramPacket dp = new DatagramPacket(args[0].getBytes(), args[0].length(), InetAddress
.getByName("172.16.22.250"), 4501);
dsSend.send(dp);
dsSend.close();
dsReceive.setSoTimeout(2000);
dsReceive.receive(dpReceive);
System.out.println(new String(dpReceive.getData(), 0, dpReceive
.getLength()));
dsReceive.close();


} catch (SocketException e) ...{
e.printStackTrace();

} catch (UnknownHostException e) ...{
e.printStackTrace();

} catch (IOException e) ...{

if(e instanceof SocketTimeoutException)...{
System.out.println("time out");
return;
}
e.printStackTrace();
}
2.服务器端功能扩展(HashMap)
想实现在server端使用map集合存储客户端数据包发送过来的用户名和客户端的IP地址,所以试着自己查阅SDK使用HashMap,其中put函数很方便地就将一些信息压入map中,在打印输出的时候遇到一点问题:尝试着直接使用System.out.println(map)结果很方便地输出来,可是这并不是一个真正程序员的作风,看来java肯定重写了map的toString函数,在SDK的压缩包中找到了HashMap的源码,看了几遍后发现比较复杂,而且还使用到一个Map.Entry的类,不想过多涉及了,打算自己动手写打印输出的功能。看到HashMap中有一个返还Set类型的KeySet函数,于是新建了一个Set集合,把KeySet保存进去,然后用迭代器迭代这个集合,获得Key集合所有元素,再用HashMap的get函数来get这个key集合中的每一个元素,获得整个Map的Value,这样一来就可以自己控制输出格式了,代码如下:
Set keyset = map.keySet();
Iterator it = keyset.iterator();

try ...{
DatagramSocket dsReceive = new DatagramSocket(4501);
DatagramSocket dsSend = new DatagramSocket();
DatagramPacket dpreceive = new DatagramPacket(buf, 100);
DatagramPacket dpsend;

while (true) ...{
dsReceive.receive(dpreceive);
map.put(new String(dpreceive.getData(), 0, dpreceive
.getLength()), dpreceive.getAddress().toString());
dpsend = new DatagramPacket("Welcome".getBytes(), "Welcome"
.length(), dpreceive.getAddress(), 4502);
dsSend.send(dpsend);
if (map.size() % 3 == 0)

while (it.hasNext()) ...{
String key = (String) it.next();
System.out.println(key + "->" + map.get(key));
}
}

} catch (SocketException e) ...{
e.printStackTrace();

} catch (UnknownHostException e1) ...{
e1.printStackTrace();

} catch (IOException e) ...{
e.printStackTrace();
}