使用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避免出现类似的错误。

 

posted @ 2019-02-19 22:37  Bug研发工程师  阅读(679)  评论(0编辑  收藏  举报