Java利用TCP實(shí)現(xiàn)服務(wù)端向客戶端消息群發(fā)的示例代碼
前言
項(xiàng)目需要和第三方廠商的服務(wù)需要用TCP協(xié)議通訊,考慮到彼此雙方可能都會有斷網(wǎng)重連、宕機(jī)重啟的情況,需要保證 發(fā)生上述情況后,服務(wù)之間能夠自動實(shí)現(xiàn)重新通信。研究測試之后整理如下代碼實(shí)現(xiàn)。因?yàn)榘l(fā)現(xiàn)客戶端重啟后,對于服務(wù)端來說原來的客戶端和服務(wù)端進(jìn)程進(jìn)程已經(jīng)關(guān)閉,啟動又和服務(wù)端新開了一個(gè)進(jìn)程。所以實(shí)現(xiàn)原理就可以通過服務(wù)端向客戶端群發(fā)實(shí)現(xiàn),斷開重新連接通訊。
代碼
tcp服務(wù)端代碼
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class HttpSocketServer {
public static void main(String[] args) {
try {
ServerSocket server=new ServerSocket(9020);
while (true){
Socket client=server.accept();
System.out.println("進(jìn)入了1個(gè)客戶機(jī)連接:"+client.getRemoteSocketAddress().toString());
ServerThread st = new ServerThread(client);
st.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
ServerThread 線程類
import java.io.*;
import java.net.Socket;
/**
* 客戶機(jī) 線程 ——自動執(zhí)行run
* @author Lenovo
*/
public class ServerThread extends Thread{
private Socket client;
/**
* 方法描述: 用有參構(gòu)造 接收主函數(shù)那邊傳來的 客戶機(jī)
*/
public ServerThread(Socket client) {
this.client=client;
}
@Override
public void run() {
try {
processSocket();//調(diào)用你想執(zhí)行的 使線程啟動時(shí)在run方法開始執(zhí)行
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 調(diào)用以上方法
*/
public void processSocket() throws IOException {
//加入集合 便于服務(wù)器群發(fā)
TcpTool.addSocket(client);
}
TcpTool 消息群發(fā)工具類
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
* 聊天工具類
* @author tarzan
*/
public class TcpTool {
private static List<Socket> clientList=new ArrayList<Socket>();
/**
* 便于 驗(yàn)證成功后 加入客戶機(jī)
* @param socket
*/
public static void addSocket(Socket socket) {
clientList.add(socket);
}
/**
* 群發(fā)=遍歷list中的all元素, 對每個(gè)元素 寫出
* @param msg
* @throws IOException
*/
public static void sendAll(String msg){
for (int i = 0; i <clientList.size(); i++) {
Socket client = clientList.get(i);
if(clientIsClose(client)){
delSocket(client);
i--;
continue;
}
try {
OutputStream ops = client.getOutputStream();
ops.write((msg+"\r\n").getBytes());
ops.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 判斷是否斷開連接,斷開返回true,沒有返回false
* @param socket
* @return
*/
public static Boolean clientIsClose(Socket socket){
try{
//發(fā)送1個(gè)字節(jié)的緊急數(shù)據(jù),默認(rèn)情況下,服務(wù)器端沒有開啟緊急數(shù)據(jù)處理,不影響正常通信
socket.sendUrgentData(0xFF);
// 發(fā)送一個(gè)數(shù)據(jù)包, 如果通信正常就不會報(bào)錯. 沒有報(bào)錯說明沒有關(guān)閉., 返回false
return false;
}catch(Exception se){
return true;
}
}
/**
* 下線時(shí)刪除
* @param socket
*/
public static void delSocket(Socket socket){
clientList.remove(socket);
}
}
Tcp客戶端代碼
import org.springblade.core.tool.utils.StringUtil;
import java.io.*;
import java.net.Socket;
/**
* @author tarzan
*/
public class HttpSocketClient {
public static void main(String[] args) throws IOException {
Socket client=new Socket("127.0.0.1",9020);
while (true) {
try {
if (!clientIsClose(client)) {
InputStream is=client.getInputStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(is));
String text=reader.readLine();
if(StringUtil.isNotBlank(text)){
System.out.println("來自服務(wù)端的消息:"+text);
}
}else{
try {
//斷開5秒后重新連接
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
client=new Socket("127.0.0.1",9020);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static Boolean clientIsClose(Socket socket){
try{
//發(fā)送1個(gè)字節(jié)的緊急數(shù)據(jù),默認(rèn)情況下,服務(wù)器端沒有開啟緊急數(shù)據(jù)處理,不影響正常通信
socket.sendUrgentData(0xFF);
// 發(fā)送一個(gè)數(shù)據(jù)包, 如果通信正常就不會報(bào)錯. 沒有報(bào)錯說明沒有關(guān)閉., 返回false
return false;
}catch(Exception se){
return true;
}
}
運(yùn)行一個(gè)服務(wù)端,啟動多個(gè)客戶端進(jìn)行測試。
控制臺輸出

以上只是實(shí)現(xiàn)的最簡單的demo,服務(wù)端,因?yàn)榉?wù)端和客戶端都需要不斷監(jiān)聽彼此通信,發(fā)送消息時(shí)候,需要另起一個(gè)線程,調(diào)用TcpTool工具類想客戶端群發(fā)消息。
到此這篇關(guān)于Java利用TCP實(shí)現(xiàn)服務(wù)端向客戶端消息群發(fā)的示例代碼的文章就介紹到這了,更多相關(guān)Java TCP消息群發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go?Java算法之為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級實(shí)例
這篇文章主要為大家介紹了Go?Java算法之為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Netty分布式高性能工具類recycler的使用及創(chuàng)建
這篇文章主要為大家介紹了Netty分布式高性能工具類recycler的使用和創(chuàng)建,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(7)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07
Java實(shí)現(xiàn)反轉(zhuǎn)義的示例代碼
本文主要介紹了Java實(shí)現(xiàn)反轉(zhuǎn)義的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-02-02
Java數(shù)據(jù)結(jié)構(gòu)與算法之選擇排序(動力節(jié)點(diǎn)java學(xué)院整理)
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法之選擇排序的相關(guān)資料,本文通過代碼講解,非常不錯,具有參考借鑒價(jià)值,需要的的朋友參考下2017-04-04
javafx tableview鼠標(biāo)觸發(fā)更新屬性詳解
這篇文章主要為大家詳細(xì)介紹了javafx tableview鼠標(biāo)觸發(fā)更新屬性的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08

