socket實現客戶端和客戶端之間通訊和聊天
阿新 • • 發佈:2018-12-30
1.實體類
package edu.tcu.cn; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class User { private String name; private String account; private Socket socket; private BufferedReader br; private PrintWriter pw; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public Socket getSocket() { return socket; } public void setSocket(final Socket socket) { this.socket = socket; } public BufferedReader getBr() { return br; } public void setBr(BufferedReader br) { this.br = br; } public PrintWriter getPw() { return pw; } public void setPw(PrintWriter pw) { this.pw = pw; } public User(String name, final Socket socket) throws IOException { this.name = name; this.socket = socket; this.br = new BufferedReader(new InputStreamReader( socket.getInputStream())); this.pw = new PrintWriter(socket.getOutputStream()); } @Override public String toString() { return "User [name=" + name + ", account=" + account + ", socket=" + socket + "]"; } }
2.服務端
服務端接收資訊並轉發的執行緒package edu.tcu.cn; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; //伺服器類 public class Server { public static void main(String[] args) throws Exception { // 例項化一個list,用於儲存所有的User List<User> list = new ArrayList<User>(); // 建立繫結到特定埠的伺服器套接字 @SuppressWarnings("resource") ServerSocket serverSocket = new ServerSocket(9999); System.out.println("服務端正在開始~"); // 迴圈監聽客戶端連線 while (true) { Socket socket = serverSocket.accept(); // 每接受一個執行緒,就隨機生成一個一個新使用者 User user = new User("user" + Math.round(Math.random() * 100),socket); System.out.println(user.getName() + "正在登入。。。"); list.add(user); // 建立一個新的執行緒,接收資訊並轉發 ServerThread thread = new ServerThread(user, list); thread.start(); } } }
package edu.tcu.cn; import java.io.IOException; import java.io.PrintWriter; import java.util.List; /* * 伺服器執行緒的作用主要是: * 1.接收來自客戶端的資訊 * 2.將接收到的資訊解析,並轉發給目標客戶端 * */ public class ServerThread extends Thread { private User user; private List<User> list; public ServerThread(User user, List<User> list) { this.user = user; this.list = list; } public void run() { try { while (true) { // 資訊的格式:(login||logout||say),傳送人,收發人,資訊體 //不斷地讀取客戶端發過來的資訊 String msg= user.getBr().readLine(); System.out.println(msg); String[] str = msg.split(","); switch (str[0]) { case "logout": remove(user);// 移除使用者 break; case "say": sendToClient(str[1], msg); // 轉發資訊給特定的使用者 break; default: break; } } } catch (Exception e) { System.out.println("異常"); } finally { try { user.getBr().close(); user.getSocket().close(); } catch (IOException e) { e.printStackTrace(); } } } private void sendToClient(String username, String msg) { for (User user : list) { if (user.getName().equals(username)) { try { PrintWriter pw =user.getPw(); pw.println(msg); pw.flush(); } catch (Exception e) { e.printStackTrace(); } } } } private void remove(User user2) { list.remove(user2); } }
3.客戶端
package edu.tcu.cn;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/*
* client執行緒主要是負責:
* 1.傳送資訊
* 2.一直接收資訊,並解析
* */
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 9999);
//開啟一個執行緒接收資訊,並解析
ClientThread thread=new ClientThread(socket);
thread.start();
//主執行緒用來發送資訊
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
PrintWriter out=new PrintWriter(socket.getOutputStream());
while(true)
{
String s=br.readLine();
out.println(s);
// out.write(s+"\n");
out.flush();
}
}catch(Exception e){
System.out.println("伺服器異常");
}
}
}
客戶端接收資訊並解析資訊執行緒package edu.tcu.cn;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* 作用:一直接收服務端轉發過來的資訊
* */
public class ClientThread extends Thread {
private Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(
inputStream);
BufferedReader br = new BufferedReader(inputStreamReader);
try {
// 資訊的格式:(login||logout||say),傳送人,收發人,資訊體
while (true) {
String msg=br.readLine();
System.out.println(msg);
String[] str = msg.split(",");
switch (str[0]) {
case "say":
System.out.println(str[2] + " 對 " + str[1] + " say: "
+ str[3]);
break;
default:
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
前天晚上看見朋友在寫,我也是一時興起。第二天就搞了一個,在弄這個的時候,遇到的一個錯。很什麼。。噁心。就是那個用readline()讀快取流的時候,真不知道其實它已經被阻塞了。當你使用readline()的時候,因為它會等待換行結束符,如果沒有換行符的時候它會一直阻塞在那裡。解決辦法:在後面加上system.out.println();實質就是在readline()之後要有換行列印的語句,否則就會阻塞。還有一個小問題:就是在client端往socket寫進資料資訊的,我上面用來了out.println(msg),然後flush(),我一開始是用out.write(msg)的,然後flush(),這樣用的其實也是被阻塞了,因為在這之前用readline(),所以後面要有換行輸出的語句,在這裡有兩種方法:1.用來了out.println(msg),然後flush();2.out.write(msg+"\n")即加上換行符,然後flush()。其實out.println和write()有點小區別,簡單的說:println=write()+newline()。
服務端:
客戶端 (發)
客戶端(收)