JavaSE版聊天室項目

JavaSE聊天室小項目

 

使用TCP編程實現客戶端和服務器端的不斷交互

 

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 *   客戶端
 * */
public class ChatRoomClient {

	public static void main(String[] args) {
		
		try {
			//創建Socket對象
			Socket s = new Socket("127.0.0.1",12345);
			
			//獲取客戶端通道的輸出和輸入流
			InputStream in = s.getInputStream();
			OutputStream out = s.getOutputStream();
			
			//創建鍵盤錄入對象
			Scanner sc = new  Scanner(System.in);
			
			//客戶端不斷的發送消息
			while(true) {
				System.out.println("請輸入消息:");
				String msg = sc.nextLine();
				//使用輸出流發送過去
				out.write(msg.getBytes());
				
				//客戶端讀取服務器發送的消息
				byte [] bys = new byte [1024];
				int len = in.read(bys);
				String msgStr = new String(bys, 0, len);
				System.out.println(msgStr);
			}
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

 

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
 * 服務器端
 * */
public class ChatRoomServer {

	public static void main(String[] args) {
		
		try {
			//創建服務器端Socket對象
			ServerSocket ss = new ServerSocket(12345);
			//監聽客戶端
			Socket s = ss.accept();
			//獲取服務器端通道的輸出和輸入流
			InputStream in = s.getInputStream();
			OutputStream out = s.getOutputStream();
			
			//創建鍵盤錄入對象
			Scanner sc = new  Scanner(System.in);
			
			//服務器端不斷的讀取消息和回覆消息
			while(true) {
				
				//讀消息
				byte [] bys = new byte [1024];
				int len = in.read(bys);
				String msg = new String(bys, 0, len);
				System.out.println(msg);
				//回覆消息
				System.out.println("請回復消息:");
				String msgStr = sc.nextLine();
				out.write(msgStr.getBytes());
			}	
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


這樣做有問題,客戶端和服務器端的讀發消息都在一個線程,可能會出現互相等待的問題

 

 

改進:將讀消息放在子線程裏面(規定)

客戶端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
 * 客戶端
 * @author dreamer_96
 */
public class ChatRoomClient {

	public static void main(String[] args) {
		
		try {
			//創建Socket對象
			Socket s = new Socket("127.0.0.1",12345);
			
			//獲取客戶端通道的輸出和輸入流
			InputStream in = s.getInputStream();
			OutputStream out = s.getOutputStream();
			
			//創建鍵盤錄入對象
			Scanner sc = new  Scanner(System.in);
			
			//開啓讀消息子線程
			ClientThread ct = new ClientThread(in);
			ct.start();
			//客戶端不斷的發送消息
			while(true) {
				System.out.println("請輸入消息:");
				String msg = sc.nextLine();
				//使用輸出流發送過去
				out.write(msg.getBytes());
			}	
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

客戶端讀消息子線程

import java.io.IOException;
import java.io.InputStream;
/**
 * 客戶端讀取消息的子線程
 * @author dreamer_96
 */
public class ClientThread extends Thread {

	private InputStream in ;

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

	@Override
	public void run() {
		
		try {
			while(true) {
				//客戶端不斷讀取服務器發送的消息
				byte [] bys = new byte [1024];
				int len = in.read(bys);
				String msgStr = new String(bys, 0, len);
				System.out.println(msgStr);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
}


服務器端

 

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
 * 服務器端
 * @author dreamer_96
 */
 
public class ChatRoomServer {

	public static void main(String[] args) {
		
		try {
			//創建服務器端Socket對象
			ServerSocket ss = new ServerSocket(12345);
			//監聽客戶端
			Socket s = ss.accept();
			//獲取服務器端通道的輸出和輸入流
			InputStream in = s.getInputStream();
			OutputStream out = s.getOutputStream();
			
			//創建鍵盤錄入對象
			Scanner sc = new  Scanner(System.in);
			
			//開啓子線程
			ServerThread st = new ServerThread(in);
			st.start();
			//服務器端不斷的讀取消息和回覆消息
			while(true) {
				//回覆消息
				System.out.println("請回復消息:");
				String msgStr = sc.nextLine();
				out.write(msgStr.getBytes());
			}	
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


服務器端讀消息子線程

 

import java.io.IOException;
import java.io.InputStream;

/**
 * 服務器端讀取消息的子線程
 * @author dreamer_96
 */
public class ServerThread extends Thread {

	private InputStream in;
	
	public ServerThread(InputStream in) {
		this.in= in ;
	}

	@Override
	public void run() {
		try {
			while(true) {
				//讀取客戶端發送的消息
				byte [] bys = new byte [1024];
				int len = in.read(bys);
				String msg = new String(bys, 0, len);
				System.out.println(msg);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	
	}	
}


使用ArrayList集合存儲Socket對象

 

服務器端

 

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * 服務器端
 * @author dreamer_96
 */
 
public class ChatRoomServer {

	public static void main(String[] args) {
		
		try {
			//創建服務器端Socket對象
			ServerSocket ss = new ServerSocket(12345);
			
			//創建ArrayList集合;分別保存每個通道內的Socket對象
			ArrayList<Socket> list = new ArrayList<Socket>();
			System.out.println("等待客戶端連接,請稍後....");
			
			int i = 1;
			while(true) {
				
				//監聽客戶端
				Socket s = ss.accept();
				System.out.println("第"+(i++)+"個客戶端已連接");
				//服務器一監聽到客戶端,就跳添加到集合中
				list.add(s);
				//獲取服務器端通道的輸出和輸入流
				InputStream in = s.getInputStream();
				OutputStream out = s.getOutputStream();
				
				//開啓子線程
			//	ServerThread st = new ServerThread(in);
				ServerThread st = new ServerThread(s,list);
				st.start();
			}
			
			/*//創建鍵盤錄入對象
			Scanner sc = new  Scanner(System.in);
			//服務器端不斷的讀取消息和回覆消息
			while(true) {
				//回覆消息
				System.out.println("請回復消息:");
				String msgStr = sc.nextLine();
				out.write(msgStr.getBytes());
			}*/	
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


服務器端讀消息子線程

 

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;

/**
 * 服務器端讀取消息的子線程
 * @author dreamer_96
 */
public class ServerThread extends Thread {

	/*private InputStream in;
	
	public ServerThread(InputStream in) {
		this.in= in ;
	}*/

	private Socket s;
	private ArrayList<Socket> list;
	
	public ServerThread(Socket s, ArrayList<Socket> list) {
		this.s = s;
		this.list = list;
	}

	@Override
	public void run() {
		try {
			//獲取通道內的輸入輸出流		
			InputStream in = s.getInputStream();
			OutputStream out = s.getOutputStream();
			while(true) {
				//讀取客戶端發送的消息
				byte [] bys = new byte [1024];
				int len = in.read(bys);
				String msg = new String(bys, 0, len);
				//msg現在的格式:  接收者:消息內容:發送者
				System.out.println(msg);
				
				//將消息拆分
				String[] msgs = msg.split(":");
			
				Socket socket = list.get(Integer.parseInt(msgs[0]));
				//獲取輸出流,寫過去
				OutputStream os = socket.getOutputStream();
				os.write((msgs[2]+"對你說"+msgs[1]).getBytes());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	
	}	
}


客戶端不變,這樣做依舊有缺點,我們要遵循開發規則 “高內聚,低耦合” ;所以我們使用HashMap集合添加用戶並且增加服務器保存用戶的子線程SaveUserThread

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章