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