這是一個簡單的LAN Socket聊天程序,客戶端是Android程序。
下面是關鍵代碼和運行效果:
服務器端代碼關鍵代碼
class ChatService {
private static final int PORT = 50000;
private static HashMap<String, Socket> socketList = new HashMap<>();
private ExecutorService executorService;
private ServerSocket serverSocket;
public ChatService () {}
public void service () {
try {
serverSocket = new ServerSocket(PORT);
executorService = Executors.newCachedThreadPool();
System.out.println("server start...");
while (true) {
Socket client = serverSocket.accept();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
String username = bufferedReader.readLine();
System.out.println(username + " login");
socketList.put(username, client);
executorService.execute(new ServerThread(client , bufferedReader));
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static class ServerThread implements Runnable {
private Socket socket;
private BufferedReader bufferedReader;
private PrintWriter printWriter;
private String message;
public ServerThread (Socket socket , BufferedReader bufferedReader) throws IOException {
this.socket = socket;
this.bufferedReader = bufferedReader;
}
@Override
public void run() {
try {
while ((message = bufferedReader.readLine()) != null) {
String[] info = message.split("\\|");
if (info[2].equals("exit")) {
socketList.remove(socket);
bufferedReader.close();
if (printWriter != null) {
printWriter.close();
}
socket.close();
System.out.println(info[0] + " exit");
break;
} else {
sendMessage(info[1]);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendMessage(String to) throws IOException {
System.out.println(message);
Socket client = socketList.get(to);
if (client != null) {
printWriter = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(client.getOutputStream())) , true);
printWriter.println(message);
}
}
}
}
客戶端代碼關鍵代碼(Android)
public class MainActivity extends Activity implements OnClickListener {
private void login () {
if (etUsername.getText().toString().equals("")) {
Toast.makeText(this, "請輸入用戶名", Toast.LENGTH_LONG).show();
return;
} else {
new loginTask().execute();
}
}
private class loginTask extends AsyncTask<Void, Object, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
btLogin.setClickable(false);
try {
socket = new Socket(IP, PORT);
printWriter = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) , true);
printWriter.println(etUsername.getText().toString());
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.i(TAG, etUsername.getText().toString());
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
btSend.setClickable(true);
} else {
btLogin.setClickable(true);
}
}
}
private void send () {
if (etTo.getText().toString().equals("")
|| etMessage.getText().toString().equals("")) {
Toast.makeText(this, "請輸入完整信息", Toast.LENGTH_LONG).show();
return;
} else {
new sendTask().execute();
}
}
private class sendTask extends AsyncTask<Void, Object, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
try {
String to = etTo.getText().toString();
String message = etMessage.getText().toString();
printWriter.println(etUsername.getText().toString() + "|" + to + "|" + message);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
tvRecord.post(new Runnable() {
@Override
public void run() {
tvRecord.append("\n" + etUsername.getText().toString() + " : " + etMessage.getText().toString());
}
});
}
}
}
/**
* 接收消息
*/
private Runnable runnable = new Runnable() {
public void run() {
while (true) {
try {
if (bufferedReader != null && (strMessage = bufferedReader.readLine()) != null) {
String[] info = strMessage.split("\\|");
strMessage = info[0] + " : " + info[2];
tvRecord.post(new Runnable() {
@Override
public void run() {
tvRecord.append("\n" + strMessage);
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
}
代碼很簡單,實現的功能也很簡單,就是一個一對一的聊天,兩點比較重要:
1、線程池
2、消息格式爲:from|to|message(發送方|接受方|消息)
運行效果
服務器:
客戶端1:
客戶端2: