首页 » 技术分享 » Java:小型聊天室系统 个人设计分析总结(一)

Java:小型聊天室系统 个人设计分析总结(一)

 

设计要求:在课本第15章Java网络通信例15.3、15.4的基础上,编写完成以下功能的小型Java聊天室系统。

  1. 多客户端模式下,实现客户与客户的单独通信,要求信息通过服务器中转。
  2. 端到端的通信,实现并行模式
  3. 实现端到端的文件传输。

多客户的单独通信

  • 改进思路:在课本例15.3、15.5的基础上,实现多客户的情况下实现客户与客户之间的通信,关键在于服务器端与客户端连接时,获取与客户端一一对应的socket套接字需要在服务器端中存储起来,在客户端收或者发信息时,只要在服务端找到对应的socket即可建立连接,互相传输信息,从而使服务器在聊天过程中起到中转消息的功能。
  • 我采用的方法是创建一个ArrayList类的对象SocketRecord,将服务器获取的socket按建立连接的顺序存储起来,使用其add()get() 方法存入或获取相应的socket。
  • 过程中出现的问题:如下图所示,如客户0与客户1聊天,客户0先给客户1发送消息,此时客户1并不能及时地收到,此时,客户1若在未知的情况下回客户0一条信息,之前客户0发的消息便会同时出现。以上过程服务器端运行过程正常。
  • 原因:readline() 方法引起的阻塞问题。以下是客户端收发消息的程序片段。readline()是一个阻塞函数,当没有数据读取时就一直阻塞在那,只有当数据流关闭或者读取到“/r”“/n”“/r/n”才会返回。所以在收消息的客户端中,最初系统没有输入就会一直阻塞在if((readline=sin.readline())!=null) 不会继续执行底下收消息的动作,只有在最初本应收消息的客户端也系统输入之后,就不再阻塞,也就可以接收那条最初本应接收的消息。在这里插入图片描述
  • 解决办法:将客户端收发消息的操作分为收消息线程与发消息线程,同时实现要求二实现端到端的并行模式

并行模式

  • 改进思路:主要是对客户端收发消息的功能进行改动,客户端在与服务器通过获取对方socket套接字建立连接之后,就创建两个线程分别收发消息。收发消息分两个线程,实现并行模式使得收发消息互不影响。
  • 代码如下
package ChatBox;

import java.io.*;
import java.net.*;
import java.util.*;

/*服务器端*/
public class TalkServer {
	public static List<Socket> SocketRecord = new ArrayList<Socket>();
	// 用ArrayList记录下不同用户的Socket
	static int clientnum = 0;

	public static void main(String args[]) throws IOException {
		ServerSocket serverSocket = null;
		boolean listening = true;
		try {
			serverSocket = new ServerSocket(4700);
		} catch (IOException e) {
			System.out.println("Could not listen on port:4700.");
			System.exit(-1);
		}
		while (listening) {
			SocketRecord.add(clientnum, serverSocket.accept());
			// 将接收到的用户保存到ArrayList相应的位置中
			new ServerThread(SocketRecord.get(clientnum), clientnum).start();// 启动相应线程
			clientnum++;
		}
		serverSocket.close();
	}
}

/*服务器的线程*/
public class ServerThread extends Thread {
	Socket socket = null;// 发消息客户端的socket
	Socket receive_socket = null;// 接收消息客户端的socket
	int Label;// 标记当前客户端编号
	int clientnum;

	public ServerThread(Socket socket, int num) {
		this.socket = socket;
		clientnum = num + 1;
		Label = num;// Label是从0开始的
	}

	public void run() {
		try {
			BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			while (true) {
				String line = is.readLine();
				String[] talkTo = line.split(" ");
				// 输入中用空格把向谁发消息和消息的内容分隔开,分别存入数组中
				int number = Integer.parseInt(talkTo[0]);
				// 用number记录当前向谁发消息
				System.out.print("Client" + Label + " is taking with Client" + number + ": ");
				System.out.println(talkTo[1]);
				receive_socket = TalkServer.SocketRecord.get(number);
				// 获得接收消息的客户端的socket
				PrintWriter os = new PrintWriter(receive_socket.getOutputStream());
				os.println(Label + " " + talkTo[1]);
				// 消息发送给接收的客户端
				os.flush();
				if (talkTo[1].equals("bye")) {
					os.close();
					break;
				}
			}
			is.close();
			socket.close();
		} catch (Exception e) {
			System.out.println("Error:" + e);
		}
	}
}

/*客户端*/
public class TalkClient {
	public static void main(String args[]) {
		try {
			Socket socket = new Socket("127.0.0.1", 4700);
			System.out.println(socket);
			new Thread(new ReceiveClient(socket.getInputStream())).start();// 收消息的线程
			new Thread(new SendClient(socket.getOutputStream())).start();// 发消息的线程
		} catch (Exception e) {
			System.out.println("Error" + e);
		}
	}
}

// 客户收消息的线程
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class ReceiveClient extends Thread {
	InputStream in;
	String socketline;

	public ReceiveClient(InputStream in) {
		this.in = in;
	}

	public void run() {
		try {
			BufferedReader is = new BufferedReader(new InputStreamReader(in));

			while (true) {
				if ((socketline = is.readLine()) != null)// 收消息
				{
					String[] istalk = socketline.split(" ");
					System.out.println(istalk[0] + ": " + istalk[1]);
				}
				if (socketline.equals("bye") || socketline == null)
					break;
			}
			is.close();
		} catch (Exception e) {
			System.out.println("Error" + e);
		}
	}
}

//客户发消息的线程
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;

public class SendClient extends Thread {
	OutputStream out;
	String[] mytalk;
	String readline;

	public SendClient(OutputStream out) {
		this.out = out;
	}

	public void run() {
		try {
			BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
			// 系统输入
			PrintWriter os = new PrintWriter(out);
			// 由Socket对象得到输出

			System.out.println("Who and What? Like'0 xxxxx.'");
			String[] mytalk;
			while (true) {
				if ((readline = sin.readLine()) != null)// 系统输入
				{
					mytalk = readline.split(" ");
					os.println(readline);
					os.flush();
					System.out.println("me: " + mytalk[1]);
				}
				if (readline.equals("bye") || readline == null)
					break;// 系统输入为bye则结束对话

			}
			os.close();
		} catch (Exception e) {
			System.out.println("Error" + e);
		}
	}
}

运行结果如下:

  • 服务器端
    在这里插入图片描述
  • 客户端0
    在这里插入图片描述
  • 客户端1
  • 客户端2
    在这里插入图片描述
    关于文件传输的在下篇更~

转载自原文链接, 如需删除请联系管理员。

原文链接:Java:小型聊天室系统 个人设计分析总结(一),转载请注明来源!

0