socket編程時(shí)的發(fā)送與接收數(shù)據(jù)時(shí)的問題解析
socket 編程時(shí)的發(fā)送與接收數(shù)據(jù)時(shí)的問題
在編寫一個(gè)測試方法時(shí),需要用啟動(dòng)一個(gè)程序監(jiān)聽一個(gè)端口,測試發(fā)送的數(shù)據(jù)是事正常,但是總是出現(xiàn)兩個(gè)問題,一是 Socked 總是在 OutputSteam.write () 方法之前被關(guān)閉,但是沒有使用代碼調(diào)用 Socket 的 Close 方法,另一個(gè)是在接收數(shù)據(jù)時(shí),總是卡在 InputSteam.read () 方法處 (一般發(fā)生在前一個(gè) Socket 在寫數(shù)據(jù)時(shí)異常中斷后再次有新 Socket 連接時(shí)),得不到數(shù)據(jù),直到發(fā)送端關(guān)閉 Socket, 下面是代碼
package com.zoro.example.subscribe.queue;
import com.zoro.util.SendUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
/**
* @author zoro
* @version 1.0
*/
public class TestSubscribeQueue {
private static final Logger LOGGER = LoggerFactory.getLogger(TestSubscribeQueue.class);
public static void main(String[] args) throws IOException {
new Thread(new EventListener()).start();
}
private static String test(InputStream is) {
BufferedReader br = null;
InputStreamReader isr = null;
StringBuilder sb = new StringBuilder();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String line = null;
while (true) {
try {
line = br.readLine();
if (line == null || line.length() == 0) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
sb.append(line);
sb.append("\n");
line = null;
LOGGER.debug("當(dāng)前讀取的數(shù)據(jù):{}", sb.toString());
}
return sb.toString();
}
static class EventListener implements Runnable {
private final ServerSocket ss;
public EventListener() throws IOException {
ss = new ServerSocket(8087);
}
@Override
public void run() {
while (true) {
/*
這里得到的InputStream 不能在OutputStream返回?cái)?shù)據(jù)之前關(guān)閉,因?yàn)镮nputStream關(guān)閉之后會(huì)導(dǎo)致Socket關(guān)閉,你說奇怪不奇怪,這樣一來就不能正常返回?cái)?shù)據(jù)了,報(bào)錯(cuò)說Socket已經(jīng)關(guān)閉
*/
try (Socket s = ss.accept();
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream()) {
LOGGER.debug("等待請求...");
LOGGER.debug("新請求進(jìn)入");
if (s.isClosed() || !s.isConnected() || s.isInputShutdown()) {
continue;
}
// String result = SendUtil.resolveInputStream(is);
String result = test(is);
LOGGER.debug("收到請求:{}", result);
StringBuilder response = new StringBuilder();
response.append("HTTP/1.1 200 OK\r\n");
response.append("Content-Type:text/html\r\n");
response.append("\r\n");
response.append("123252321");
LOGGER.debug("即將返回?cái)?shù)據(jù):{}", response.toString());
if (!s.isClosed()) {
LOGGER.debug("正在返回?cái)?shù)據(jù)");
os.write(response.toString().getBytes());
os.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}分析原因
- 在第 76 行代碼調(diào)用的方法中 調(diào)用的 InputStream.close () 方法,導(dǎo)致了 Socket 也跟著關(guān)閉了,不清楚是什么原因引起的,但是去掉 InputStream.close () 確實(shí) OutputStream 可以向請求端改善數(shù)據(jù)了
- 在 OutputStream 的問題解決之后,InputStream 的問題也跟著沒有了,因?yàn)槲以跍y試時(shí)使用的是瀏覽器 http 發(fā)起的這個(gè) Socket,所以我猜測是在第一次 Socket 異常中斷后瀏覽器再次觸發(fā)了重試;;
問題更新
兩天后發(fā)現(xiàn)新問題: InputStream 在包裝成 BufferedReader 整行讀取時(shí)到 http 請求的最后一行還會(huì)繼續(xù)向下一行讀,但是發(fā)送端這時(shí)已經(jīng)不發(fā)送數(shù)據(jù)了,造成服務(wù)端一直卡在這里等待
問題原因
BufferedReader.readLine () 方法在讀取文件只,因?yàn)槲募詈髸?huì)是一個(gè) - 1 ,所以可以知道在哪里結(jié)束,但網(wǎng)絡(luò)請求最后沒有這個(gè) - 1 所以在讀了最后一行后不知道請求數(shù)據(jù)已經(jīng)沒有更多了,造成一直阻塞
解決思路
http 請求(只討論 get 與 post 兩種方法),get 請求只有請求頭,在讀取到第一個(gè)空行時(shí)就可以結(jié)束,post 請求有請求體,可以根據(jù)請求頭中 ContentLength 判斷是否讀取完
以上就是socket編程時(shí)的發(fā)送與接收數(shù)據(jù)時(shí)的問題解析的詳細(xì)內(nèi)容,更多關(guān)于socket發(fā)送接收數(shù)據(jù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Validation方法實(shí)現(xiàn)原理分析
這篇文章主要介紹了Spring Validation實(shí)現(xiàn)原理分析,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07
SpringBoot2.0集成MQTT消息推送功能實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot2.0集成MQTT消息推送功能實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Java通過導(dǎo)出超大Excel文件解決內(nèi)存溢出問題
導(dǎo)出excel是咱Java開發(fā)的必備技能,下面這篇文章主要給大家介紹了關(guān)于Java通過導(dǎo)出超大Excel文件解決內(nèi)存溢出問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09
Java實(shí)現(xiàn)兩人五子棋游戲(七) 屏幕提示信息
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)兩人五子棋游戲,屏幕提示游戲信息,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
Idea啟動(dòng)SpringBoot程序報(bào)錯(cuò):Veb server failed to&nbs
這篇文章主要介紹了Idea啟動(dòng)SpringBoot程序報(bào)錯(cuò):Veb server failed to start. Port 8082 was already in use;端口沖突的原理與解決方案,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2024-10-10
Java instanceof關(guān)鍵字的的進(jìn)一步理解
這篇文章主要介紹了Java instanceof關(guān)鍵字的的進(jìn)一步理解,本文用一些實(shí)例講解了instanceof操作符的一些知識(shí),需要的朋友可以參考下2015-03-03
MybatisPlus實(shí)現(xiàn)數(shù)據(jù)攔截的使用示例
在MyBatis-Plus中,可以通過自定義攔截器來實(shí)現(xiàn)對SQL語句的攔截和修改,本文就來介紹一下如何使用,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10
Java設(shè)計(jì)模式之外觀模式(Facade模式)介紹
這篇文章主要介紹了Java設(shè)計(jì)模式之外觀模式(Facade模式)介紹,外觀模式(Facade)的定義:為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,需要的朋友可以參考下2015-03-03
Spring Cloud Gateway 緩存區(qū)異常問題及解決方案
最近在測試環(huán)境spring cloud gateway突然出現(xiàn)了異常,接下來通過本文給大家介紹Spring Cloud Gateway 緩存區(qū)異常問題解決方案,需要的朋友可以參考下2024-06-06

