客戶端之間通訊: 實際上兩個客戶端不能直接通訊,要藉助服務器來作爲中轉站,才能實現雙方通訊。服務器
一個客戶端發送數據到服務器,服務器將數據發送給(全部鏈接上服務器的)客戶端,這樣客戶端之間實現了通訊。socket
服務器的代碼:tcp
public class PcService {
private static final int SERVICEPORT=10086;
private static ArrayList<Socket> mClientList=new ArrayList<Socket>(); //記錄鏈接上服務器的客戶端
private ExecutorService mExecutorService; //建立線程池來管理
private ServerSocket serverSocket;
public static void main(String[] args) {
new PcService();
}
public PcService() {
try {
serverSocket=new ServerSocket(SERVICEPORT);
mExecutorService=Executors.newCachedThreadPool();
Socket clientSocket=null;
while(true){ //一接受到客戶端發送來的數據,馬上將信息轉發給全部鏈接在線的客戶端
clientSocket=serverSocket.accept();
mClientList.add(clientSocket);
mExecutorService.execute(new ThreadServer(clientSocket));
}
}
catch (Exception e) {
e.printStackTrace();
}
}
this
static class ThreadServer implements Runnable{
PrintWriter printWriter;
BufferedReader bufferedReader;
String message;
Socket socket;線程
public ThreadServer(Socket socket) throws IOException {
this.socket=socket;
bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
message=this.socket.getInetAddress()+"";
sendMessageToClient();
}
public void run() {
try {
while((message=bufferedReader.readLine())!=null){
if(message.trim().equals("exit")){//當一個客戶端退出時
mClientList.remove(socket);
bufferedReader.close();server
printWriter.close();
socket.close();
sendMessageToClient();
break ;
}
else{
message=socket.getInetAddress()+"";
sendMessageToClient();
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
//發送消息給每個鏈接的客戶端
private void sendMessageToClient(){
try {
for(Socket client:mClientList){
printWriter=new PrintWriter(client.getOutputStream());
printWriter.println( message );
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}rem
監控TCP的狀態: 心跳包get
作法:一個單獨線程(心跳線程),來維護tcp的鏈接。
每隔一個時間就向服務器/客戶端發送一段鏈接信息,當對方接受到後立刻回覆對方。而後設置一個超時時間it
,過個時間就反覆發幾回。若是沒有收到回覆,則斷定tcp斷開了。io
用心跳包來維護鏈接,在發送心跳包異常時,能夠認爲對方短線,
或者指定時間超時後,未收到對方的心跳響應,也認爲是對方短線。 或者就是Send的時候會直接報異常,能夠直接認爲是掉線了。