使用java网络编程模拟简单网络即时通信
使用java网络编程模拟简单网络即时通信
通信流程图:
解析:
1.在上图中我们可以看出对于任何一个客户端,都由两部分构成,发送端和接收端(分别由两个线程来维系)
2.客户端在每一次请求链接时都会轮询,向服务器发送请求,服务器发回当前在线列表
3.服务器端使用线程池技术为每一个连接请求创建一个线程去处理。
4.在客户端与服务器之间使用TCP通讯,可靠通信
5.在用户之间使用UDP报文来传输数据。
代码实现:
Chat类:
package cn.csuft.poorguy.homework; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Scanner; import com.alibaba.fastjson.JSON; import com.google.gson.Gson; public class Chat { Thread sender; Thread receiver; DatagramSocket udpSocket; Socket tcpSocket; public Chat() { try { Scanner cin = new Scanner(System.in); System.out.println("昵称:"); String nick = cin.nextLine(); //TODD C/S tcpSocket = new Socket("127.0.0.1",9000); InputStream in = tcpSocket.getInputStream(); OutputStream out = tcpSocket.getOutputStream(); //发送自己的昵称和端口 udpSocket = new DatagramSocket(); int udpPort = udpSocket.getLocalPort(); String msg = new String(nick+","+udpPort); out.write(msg.getBytes()); out.flush(); //接收在线用户的列表 byte []buf = new byte[1024]; int size = in.read(buf); String json = new String(buf,0,size); //HashMap<String, Integer> users = new Gson().fromJson(json,HashMap.class); HashMap<String, Integer> users = JSON.parseObject(json, HashMap.class); System.out.println("在线列表 : "+users); //double p = users.get(nick).doubleValue(); //把用户列表传给SenderTask sender = new Thread(new SendTask(udpSocket,users,tcpSocket)); receiver = new Thread(new ReceiverTask(udpSocket)); sender.start(); receiver.start(); } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { Chat chat = new Chat(); } }
ChatServer类:
package cn.csuft.poorguy.homework; import java.io.IOException; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ChatServer { ServerSocket serverSocket; int serverPort = 9000; ExecutorService pool; Map<String, Integer> users = new HashMap<String, Integer>(); public ChatServer() { pool = Executors.newCachedThreadPool(); } public void start() { System.out.println("服务器启动:。。。。"); try { serverSocket = new ServerSocket(serverPort); while(true) { Socket socket = serverSocket.accept(); OnlineService onlineService = new OnlineService(socket,users); pool.execute(onlineService); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { ChatServer chatServer = new ChatServer(); chatServer.start(); } }
OnlineService类:
package cn.csuft.poorguy.homework; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.HashMap; import java.util.Map; import com.alibaba.fastjson.JSON; import com.google.gson.Gson; public class OnlineService implements Runnable{ Socket socket; Map<String, Integer> users; public OnlineService() { // TODO Auto-generated constructor stub } public OnlineService(Socket socket, Map<String, Integer> users) { this.socket = socket; this.users = users; } @Override public void run() { try (InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream()){ byte []buf = new byte[1024]; int size = in.read(buf); String msg = new String(buf,0,size); //解析出msg中的nick信息 String nick = msg.split(",")[0]; int port = Integer.parseInt(msg.split(",")[1]); //将nick与端口放入在线列表中 users.put(nick, port); //String json = new Gson().toJson(users); String json = JSON.toJSONString(users); System.out.println(json); out.write(json.getBytes()); out.flush(); } catch (Exception e) { // TODO: handle exception } } }
ReceiveTask类:
package cn.csuft.poorguy.homework; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class ReceiverTask implements Runnable { DatagramSocket socket = null; public ReceiverTask() { // TODO Auto-generated constructor stub } public ReceiverTask(DatagramSocket socket) { this.socket = socket; } @Override public void run() { String msg = null; byte []buf = new byte[1024*8]; do { DatagramPacket packet = new DatagramPacket(buf, buf.length); try { socket.receive(packet); byte []data = packet.getData(); msg = new String(data,0,packet.getLength()); System.out.println("收到: "+msg); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } while (!msg.equalsIgnoreCase("bye")); System.out.println("接收端关闭"); } }
SendTask类:
package cn.csuft.poorguy.homework; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Scanner; import com.alibaba.fastjson.JSON; public class SendTask implements Runnable { HashMap<String, Integer> users; DatagramSocket socket = null; Socket tcpSocket; public SendTask() { // TODO Auto-generated constructor stub } public SendTask(DatagramSocket socket, HashMap<String, Integer> users, Socket tcpSocket) { this.socket = socket; this.users = users; this.tcpSocket = tcpSocket; } @Override public void run() { String msg = null; Scanner cin = new Scanner(System.in); DatagramPacket packet = null; while (true) { GetUsersFromServer(); System.out.println("输入接收方:"); String nick = cin.nextLine(); if (users.containsKey(nick)) { do { int port = users.get(nick); System.out.print("发送:"); msg = cin.nextLine(); byte[] data = msg.getBytes(); try { // 创建数据包 packet = new DatagramPacket(data, data.length, InetAddress.getByName("127.0.0.1"), port); // 发送 socket.send(packet); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } while (!msg.equalsIgnoreCase("bye")); System.out.println("发送结束"); } else { System.out.println("该用户不在线"); } } } private void GetUsersFromServer() { // TODD C/S try { tcpSocket = new Socket("127.0.0.1", 9000); InputStream in = tcpSocket.getInputStream(); OutputStream out = tcpSocket.getOutputStream(); // 发送自己的昵称和端口 int udpPort = socket.getLocalPort(); String ss = new String("######" + "," + udpPort); out.write(ss.getBytes()); out.flush(); // 接收在线用户的列表 byte[] buf = new byte[1024]; int size = in.read(buf); String json = new String(buf, 0, size); // HashMap<String, Integer> users = new Gson().fromJson(json,HashMap.class); users = JSON.parseObject(json, HashMap.class); System.out.println("在线列表 : " + users); } catch (UnknownHostException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }
注意:
这里服务器发回的在线列表使用的是fastJson转换成JSON的,在这个过程中遇到了一些晓得问题,之前选用的Gson,但是发现Gson会默认将int转成double,会出现一些错误,所以改用fastJson,建议以后可以直接使用fastJson避免出现类似的错误。