Java-readLine()阻塞問(wèn)題及解決過(guò)程
socket編程中readLine()阻塞問(wèn)題
readLine()的API說(shuō)明
- public String readLIne() throws IOException
中文版:
- 讀一行文字。 一行被視為由換行符(’\ n’),回車符(’\ r’)中的任何一個(gè)或隨后的換行符終止。
- 返回:包含行的內(nèi)容的字符串,不包含任何行終止字符,如果到達(dá)流末尾,則為null
英文版:
- Reads a line of text. A line is considered to be terminated by any one of a line feed (’\n’), a carriage return (’\r’), or a carriage return followed immediately by a linefeed.
- Returns:
- A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
遇到的問(wèn)題:
- 當(dāng)使用socket寫一個(gè)雙向通信的服務(wù)端時(shí),總是接收不到來(lái)自用戶的消息,和書上比對(duì)才發(fā)現(xiàn)是readLine()的問(wèn)題,
- 還有就是客戶端和服務(wù)端的初始狀態(tài)問(wèn)題(一個(gè)為初始為“發(fā)送”,一個(gè)為“接收”)
第一種情況
- 一個(gè)客戶端,一個(gè)服務(wù)端。當(dāng)服務(wù)端使用
readLine()讀消息時(shí),需要讀到一個(gè)換行符(‘\n’,或’\r’)才會(huì)結(jié)束。否則回一直阻塞,主線程就掛在這兒了 - 解決方法:在客戶端發(fā)送消息的時(shí)候,外加一個(gè)換行符
//用戶發(fā)送消息的線程
class SentMessage extends Thread{
private Socket socket;
private BufferedWriter bw;
private BufferedReader mysc;
SentMessage(Socket socket){
this.socket = socket;
try {
bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
mysc = new BufferedReader(new InputStreamReader(System.in));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run(){
try{
while (true){
String mymessage = mysc.readLine();
bw.write(mymessage+"\n");
bw.flush();
if("bye".equals(mymessage)){
break;
}
}
}catch (IOException e){
e.printStackTrace();
}finally {
try{
if(mysc!=null){
mysc.close();
}
if(bw!=null){
bw.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
第二種
- 當(dāng)用服務(wù)器轉(zhuǎn)發(fā)來(lái)自每個(gè)用戶的消息到聊天室時(shí),如果就用一個(gè)"轉(zhuǎn)發(fā)消息"方法也會(huì)出現(xiàn)問(wèn)題,就是使用了readLine()的阻塞
- 思考:一個(gè)客戶都應(yīng)有一個(gè)自己”轉(zhuǎn)發(fā)消息“通道(線程),不和其他客戶共用一個(gè)”轉(zhuǎn)發(fā)通道“(會(huì)導(dǎo)致阻塞
- 解決,用一個(gè)線程來(lái)做轉(zhuǎn)發(fā)
//內(nèi)置線程類用于接收消息,并廣播
class AcceptMessage extends Thread{
private Socket clientsocket;
private BufferedReader br;
AcceptMessage(Socket clientsocket){
this.clientsocket = clientsocket;
}
/**
* 服務(wù)器將所有接收的消息廣播(顯示在每一個(gè)客戶的聊天窗口中
* 注意:如果這里不用線程,會(huì)出現(xiàn)問(wèn)題,思考---其實(shí)就是readLine()阻塞的問(wèn)題
*/
private void tellEveryone(Socket socket){
try{
//先從發(fā)送消息的客戶讀內(nèi)容
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = br.readLine();
chatArea.append("用戶"+socket.getPort()+": "+message+"\n");
//然后將內(nèi)容廣播到每一個(gè)客戶接口
Iterator<Socket> it = list.iterator();
while (it.hasNext()){
Socket socket2 = it.next();
//對(duì)自己就不要廣播了
if(socket!=socket2){
bw = new BufferedWriter(new OutputStreamWriter(socket2.getOutputStream()));
bw.write(socket2.getInetAddress().getHostAddress()+": "+message+"\n");
bw.flush();
}
}
}catch (IOException e){
e.printStackTrace();
}
}
@Override
public void run(){
while (true){
//接收并廣播
tellEveryone(clientsocket);
}
}
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java?@Mapper?使用注解的方式注入SQL的詳細(xì)過(guò)程
文章主要介紹了MySQL的JSON數(shù)據(jù)類型及其使用方法,包括在表中存儲(chǔ)和處理JSON數(shù)據(jù)、使用JSON數(shù)據(jù)進(jìn)行復(fù)雜查詢以及在SQL語(yǔ)句中處理JSON數(shù)據(jù)的示例,感興趣的朋友跟隨小編一起看看吧2025-12-12
Java Spring分別實(shí)現(xiàn)定時(shí)任務(wù)方法
這篇文章主要為大家詳細(xì)介紹了Java與Spring設(shè)置動(dòng)態(tài)定時(shí)任務(wù)的方法,定時(shí)任務(wù)的應(yīng)用場(chǎng)景十分廣泛,如定時(shí)清理文件、定時(shí)生成報(bào)表、定時(shí)數(shù)據(jù)同步備份等2022-07-07
JavaMap兩種遍歷方式keySet與entrySet詳解
這篇文章主要介紹了JavaMap兩種遍歷方式keySet與entrySet,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-03-03
AsyncHttpClient exception異常源碼流程解析
這篇文章主要為大家介紹了AsyncHttpClient的exception源碼流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
Java中的@RequiredArgsConstructor注解詳解
這篇文章主要介紹了Java中的@RequiredArgsConstructor注解詳解,@RequiredArgsConstructor是Lombok的一個(gè)注解,簡(jiǎn)化了我們對(duì)@Autowired書寫,@RequiredArgsConstructor注解可以代替@Autowired注解,需要的朋友可以參考下2024-01-01
Spring IOC源碼之bean的注冊(cè)過(guò)程講解
這篇文章主要介紹了Spring IOC源碼之bean的注冊(cè)過(guò)程講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Spring?Boot?整合持久層之Spring Data JPA
在介紹Spring Data JPA的時(shí)候,我們首先認(rèn)識(shí)下Hibernate。Hibernate是數(shù)據(jù)訪問(wèn)解決技術(shù)的絕對(duì)霸主,使用O/R映射技術(shù)實(shí)現(xiàn)數(shù)據(jù)訪問(wèn),O/R映射即將領(lǐng)域模型類和數(shù)據(jù)庫(kù)的表進(jìn)行映射,通過(guò)程序操作對(duì)象而實(shí)現(xiàn)表數(shù)據(jù)操作的能力,讓數(shù)據(jù)訪問(wèn)操作無(wú)須關(guān)注數(shù)據(jù)庫(kù)相關(guān)的技術(shù)2022-08-08
Java輕松使用工具類實(shí)現(xiàn)獲取wav時(shí)間長(zhǎng)度
在Java中,工具類定義了一組公共方法,這篇文章將介紹Java中使用工具類來(lái)獲取一個(gè)wav文件的時(shí)間長(zhǎng)度,感興趣的同學(xué)繼續(xù)往下閱讀吧2021-10-10
SpringBoot整合PowerJob實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度
最近項(xiàng)目需要使用定時(shí)任務(wù),而使用了PowerJob做任務(wù)調(diào)度模塊,感覺(jué)這個(gè)框架真香,今天我們就來(lái)深入了解一下新一代的定時(shí)任務(wù)框架——PowerJob,需要的朋友可以參考下2024-03-03

