首页 > 代码库 > 简单的C/S聊天室

简单的C/S聊天室

C/S聊天室分为服务器端和客户端,均需要采用多线程来实现。

服务器端主线程需要不断地监听端口,一旦有客户端的请求时,产生相应的Socket,将其加入到队列中并启动子线程,子线程负责接收客户端消息(使用Socket的getInputStream()函数来处理),再将消息发送到所有的客户端(使用Socket的getOutputStream()函数)。

客户端主线程负责获取键盘输入(相当于侦听键盘输入),并传递给Socket的输出流(使用Socket的getOutputStream(),为什么这里是getOutputStream(),因为对Socket而言是输出流),而子线程负责取得服务器端发过来的消息(使用Socket的getInputStream())。

代码如下,代码没有实现界面:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;


public class Server {

	private final int PORT=30000;
	public static ArrayList<Socket> socketList=new ArrayList<Socket>();
	public void init()
	{
		try (
			ServerSocket serverSocket=new ServerSocket(PORT);
		)
		{
			while(true)
			{
				Socket socket=serverSocket.accept();
				socketList.add(socket);
				new Thread(new ServerThread(socket)).start();
			}
		}catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("服务器启动失败,是否"+PORT+"端口已被占用?");
		}
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Server s=new Server();
		s.init();

	}

}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;



public class ServerThread implements Runnable
{
	private Socket s=null;
	private BufferedReader br=null;

	public ServerThread(Socket s)
	{
		this.s=s;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			br=new BufferedReader(new InputStreamReader(s.getInputStream()));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("Socket对应的输入流获取失败!");
		}
		String content=null;
		while((content=readFromClient())!=null)
		{
			for(Socket s:Server.socketList)
			{
				try (
					PrintStream ps=new PrintStream(s.getOutputStream()); // 让该程序通过该输出流向socket中输出数据
				)
				{
					ps.println(content);
				}catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
	}

	private String readFromClient() {
		// TODO Auto-generated method stub
		try {
			return br.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			Server.socketList.remove(s);
		}
		return null;
	}

}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;


public class Client {
	
	private final static int PORT=30000;
	private final static String host="127.0.0.1";
	
	public static void main(String[] args) throws UnknownHostException, IOException {
		// TODO Auto-generated method stub
		Socket s=new Socket(host,PORT);
		new Thread(new ClientThread(s)).start(); // 子线程完成与服务器通信
		PrintStream ps=new PrintStream(s.getOutputStream()); // 让程序通过该输出流向Socket中输出数据,得到了socket的输出流
		String line=null;
	
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		// br.readline()不断读取键盘输入内容
		while((line=br.readLine())!=null)
		{
			ps.println(line);
		}
	}

}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;


public class ClientThread implements Runnable {
	
	private Socket s=null;
	private BufferedReader br=null;
	public ClientThread(Socket s) throws IOException
	{
		this.s=s;
		br=new BufferedReader(new InputStreamReader(s.getInputStream())); // 该句只是返回了这样一个对象,里面并不包含屏幕中的语句
	}																	  // 其用readline()的时候才得到输入语句

	@Override
	public void run() {
		// TODO Auto-generated method stub
		String content=null;
		try {
			while((content=br.readLine())!=null) // readline()遇到输入末尾的时候才会返回null
			{
				System.out.println(content);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}

参考资料:疯狂JAVA讲义