❶ java socket編程 readline()讀取問題,為啥在client端剛連接上就開始無限循環,停不下來
改一下
scan.nextLine();//阻塞,排除是socket建立太慢導致的
String str=null;
這兩行刪除,沒用
str=br.readLine();
這個改成
br=scan.readLine();
然後你再試一下
順便再說一下,這個程序我寫過,我開始想的也是客戶端發送的數據伺服器端可以實時接收,但是我發現我錯了,因為Scanner 的阻塞,如果客戶端發送消息伺服器端必須也得發送一個消息才能收到,這個內容可以是任意內容,比如一個回車,如果想讓客戶端 或伺服器端可以實時接收到消息,在控制台中是不可能實現的,除非使用swing框架,一個文本框負負責發送,一個文本框負責接收,不過聽他們說swing現在企業中根本不用了,所有我也就沒有深入研究,勸你也放棄吧,研究這個沒什麼用,除非你能在網頁上實現,或者做一個程序,至於我寫的源碼,如果你要我可以發給你
對了再說下你這個問題出現的原因
你這個是因為循環中沒有阻塞語句,而且br沒有接收到值,所有它會一直列印null
❷ Java中socket填的ip
首先必須明確:TCP/IP模型中有四層結構:
應用層(Application Layer)、傳輸層(Transport Layer)、網路層(Internet Layer )、鏈路層(LinkLayer)
其中Ip協議(Internet Protocol)是位於網路層的,TCP協議時位於傳輸層的。通過Ip協議可以使可以使兩台計算機使用同一種語言,從而允許Internet上連接不同類型的計算機和不同操作系統的網路。Ip協議只保證計算機能夠接收和發送分組數據。 當計算機要和遠程的計算機建立連接時,TCP協議會讓他們建立連接:用於發送和接收數據的虛擬電路。
在JAVA中,我們用 ServerSocket、Socket類創建一個套接字連接,從套接字得到的結果是一個InputStream以及OutputStream對象,以便將連接作為一個IO流對象對待。通過IO流可以從流中讀取數據或者寫數據到流中,讀寫IO流會有異常IOException產生。
套接字或插座(socket)是一種軟體形 式的抽象,用於表達兩台機器間一個連接的「終端」。針對一個特定的連接,每台機器上都有一個「套接字」,可以想像它們之間有一條虛擬的「線纜」。JAVA 有兩個基於數據流的套接字類:ServerSocket,伺服器用它「偵聽」進入的連接;Socket,客戶端用它初始一次連接。偵聽套接字只能接收新的 連接請求,不能接收實際的數據包,即ServerSocket不能接收實際的數據包。
套接字是基於TCP/IP實現的,它是用來提供一個訪問TCP的服務介面,或者說套接字socket是TCP的應用編程介面API,通過它應用層就可以訪問TCP提供的服務。
在JAVA中,我們用 ServerSocket、Socket類創建一個套接字連接,從套接字得到的結果是一個InputStream以及OutputStream對象,以便 將連接作為一個IO流對象對待。通過IO流可以從流中讀取數據或者寫數據到流中,讀寫IO流會有異常IOException產生。
套接字底層是基於TCP的,所以socket的超時和TCP超時是相同的。下面先討論套接字讀寫緩沖區,接著討論連接建立超時、讀寫超時以及JAVA套接字編程的嵌套異常捕獲和一個超時例子程序的抓包示例。
1 socket讀寫緩沖區
一旦創建了一個套接字實例,操作系統就會為其分配緩沖區以存放接收和要發送的數據。
JAVA可以設置讀寫緩沖區的大小-setReceiveBufferSize(int size), setSendBufferSize(int size)。
向輸出流寫數據並不意味著數據實際上已經被發送,它們只是被復制到了發送緩沖區隊列SendQ,就是在Socket的OutputStream上調用 flush()方法,也不能保證數據能夠立即發送到網路。真正的數據發送是由操作系統的TCP協議棧模塊從緩沖區中取數據發送到網路來完成的。
當有數據從網路來到時,TCP協議棧模塊接收數據並放入接收緩沖區隊列RecvQ,輸入流InputStream通過read方法從RecvQ中取出數據。
2 socket連接建立超時
socket連接建立是基於TCP的連接建立過程。TCP的連接需要通過3次握手報文來完成,開始建立TCP連接時需要發送同步SYN報文,然後等待確認 報文SYN+ACK,最後再發送確認報文ACK。TCP連接的關閉通過4次揮手來完成,主動關閉TCP連接的一方發送FIN報文,等待對方的確認報文;被 動關閉的一方也發送FIN報文,然等待確認報文。
正在等待TCP連接請求的一端有一個固定長度的連接隊列,該隊列中的連接已經被TCP接受(即三次握手已經完成),但還沒有被應用層所接受。TCP接受一個連接是將其放入這個連接隊列,而應用層接受連接是將其從該隊列中移出。應用層可以通過設置backlog變數來指明該連接隊列的最大長度,即已被TCP接受而等待應用層接受的最大連接數。
當一個連接請求SYN到達時,TCP確定是否接受這個連接。如果隊列中還有空間,TCP模塊將對SYN進行確認並完成連接的建立。但應用層只有在三次握手中的第三個報文收到後才會知道這個新連接。如果隊列沒有空間,TCP將不理會收到的SYN。
如果應用層不能及時接受已被TCP接受的連接,這些連接可能占滿整個連接隊列,新的連接請求可能不被響應而會超時。如果一個連接請求SYN發送後,一段時間後沒有收到確認SYN+ACK,TCP會重傳這個連接請求SYN兩次,每次重傳的時間間隔加倍,在規定的時間內仍沒有收到SYN+ACK,TCP將放棄這個連接請求,連接建立就超時了。
JAVA Socket連接建立超時和TCP是相同的,如果TCP建立連接時三次握手超時,那麼導致Socket連接建立也就超時了。可以設置Socket連接建立的超時時間-
connect(SocketAddress endpoint, int timeout)
如果在timeout內,連接沒有建立成功,在TimeoutException異常被拋出。如果timeout的值小於三次握手的時間,那麼Socket連接永遠也不會建立。
不同的應用層有不同的連接建立過程,Socket的連接建立和TCP一樣-僅僅需要三次握手就完成連接,但有些應用程序需要交互很多信息後才能成功建立連接,比如Telnet協議,在TCP三次握手完成後,需要進行選項協商之後,Telnet連接才建立完成。
3 socket讀超時
如果輸入緩沖隊列RecvQ中沒有數據,read操作會一直阻塞而掛起線程,直到有新的數據到來或者有異常產生。調用setSoTimeout(int timeout)可以設置超時時間,如果到了超時時間仍沒有數據,read會拋出一個SocketTimeoutException,程序需要捕獲這個異 常,但是當前的socket連接仍然是有效的。
如果對方進程崩潰、對方機器突然重啟、網路斷開,本端的read會一直阻塞下去(由前面可知:雙方要關閉連接需要四次揮手 .對方機重啟或斷開只是對方機的TCP連接關閉,本端的TCP連接還沒關閉,所以本端機會一直阻塞),這時設置超時時間是非常重要的,否則調用read的線程會一直掛起。
TCP模塊把接收到的數據放入RecvQ中,直到應用層調用輸入流的read方法來讀取。如果RecvQ隊列被填滿了,這時TCP會根據滑動窗口機制通知 對方不要繼續發送數據,本端停止接收從對端發送來的數據,直到接收者應用程序調用輸入流的read方法後騰出了空間。
4 socket寫超時
socket的寫超時是基於TCP的超時重傳。超時重傳是TCP保證數據可靠性傳輸的一個重要機制,其原理是在發送一個數據報文後就開啟一個計時器,在一 定時間內如果沒有得到發送報文的確認ACK,那麼就重新發送報文。如果重新發送多次之後,仍沒有確認報文,就發送一個復位報文RST,然後關閉TCP連 接。首次數據報文發送與復位報文傳輸之間的時間差大約為9分鍾,也就是說如果9分鍾內沒有得到確認報文,就關閉連接。但是這個值是根據不同的TCP協議棧 實現而不同。
如果發送端調用write持續地寫出數據,直到SendQ隊列被填滿。如果在SendQ隊列已滿時調用write方法,則write將被阻塞,直到 SendQ有新的空閑空間為止,也就是說直到一些位元組傳輸到了接收者套接字的RecvQ中。如果此時RecvQ隊列也已經被填滿,所有操作都將停止,直到 接收端調用read方法將一些位元組傳輸到應用程序。
當Socket的write發送數據時,如果網線斷開、對端進程崩潰或者對端機器重啟動,(由前面可知:雙方要關閉連接需要四次揮手 .對端進程崩潰或者對端機器重啟動只是對方機的TCP連接關閉,本端的TCP連接還沒關閉,所以本端機會一直阻塞)TCP模塊會重傳數據,最後超時而關閉連接。下次如再調用write會導致一個異常而退出。
Socket寫超時是基於TCP協議棧的超時重傳機制,一般不需要設置write的超時時間,也沒有提供這種方法。
5 雙重嵌套異常捕獲
如果ServerSocket、Socket構造失敗,只需要僅僅捕獲這個構造失敗異常而不需要調用套接字的close方法來釋放資源(必須保證構造失敗 後不會留下任何需要清除的資源),因為這時套接字內部資源沒有被成功分配。如果構造成功,必須進入一個try finally語句塊里調用close釋放套接字。請參照下面例子程序。
import java.net.*;
import java.io.*;
public class SocketClientTest
{
public static final int PORT = 8088;
public static void main( String[] args ) throws Exception
{
InetAddress addr = InetAddress.getByName( "127.0.0.1" );
Socket socket = new Socket();
try
{
socket.connect( new InetSocketAddress( addr, PORT ), 30000 );
socket.setSendBufferSize(100);
BufferedWriter out = new BufferedWriter( new OutputStreamWriter( socket.getOutputStream() ) );
int i = 0;
while( true )
{
System.out.println( "client sent --- hello *** " + i++ );
out.write( "client sent --- hello *** " + i );
out.flush();
Thread.sleep( 1000 );
}
}
finally
{
socket.close();
}
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServerTest
{
public static final int PORT = 8088;
public static final int BACKLOG = 2;
public static void main( String[] args ) throws IOException
{
ServerSocket server = new ServerSocket( PORT, BACKLOG );
System.out.println("started: " + server);
try
{
Socket socket = server.accept();
try
{
BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
String info = null;
while( ( info = in.readLine() ) != null )
{
System.out.println( info );
}
}
finally
{
socket.close();
}
}
finally
{
server.close();
}
}
}
❸ Java socket接收緩存中多行數據數據的讀取問題
先用輸入流來InputStream將文件內容讀取到源位元組數組(長度為 1024)中,再用輸出流OutputStream將位元組數組中的數據寫到目標設備
public void write(byte[] buffer, int offset, int count)
該方法第一個參數為:位元組數組
第二個是:要寫入的數據在數組中的起始位置 即:0
第三個是:寫入的長度,即:1024
❹ java簡答題 如何創建socket連接的過程
java socket建立連接的過程如下:
socket
1、 首先調用Socket類的構造函數,以伺服器的指定的IP地址或指定的主機名和指定的埠號為參數,創建一個Socket流,在創建Socket流的過程中包含了向伺服器請求建立通訊連接的過程實現。
2、 建立了客戶端通訊Socket後。就可以使用Socket的方法getInputStream()和getOutputStream()來創建輸入/輸出流。這樣,使用Socket類後,網路輸入輸出也轉化為使用流對象的過程。
3、 使用輸入輸出流對象的相應方法讀寫位元組流數據,因為流連接著通訊所用的Socket,Socket又是和伺服器端建立連接的一個端點,因此數據將通過連接從伺服器得到或發向伺服器。這時我們就可以對位元組流數據按客戶端和伺服器之間的協議進行處理,完成雙方的通訊任務。
4、 待通訊任務完畢後,我們用流對象的close()方法來關閉用於網路通訊的輸入輸出流,在用Socket對象的close()方法來關閉Socket。
❺ java socket 讀取字元串又讀取對象
對方有沒有來完整地寫完東西自到ObjectOutputStream
並Flush了?
因為InputStream是阻塞式的,只要沒有讀取完成就會停在那兒等。
因為Socket本身是全雙工的,就是說讀和寫可以是互不相關的,不互相依賴次序,所以當我們直接使用InputStream/OutputStream這種阻塞式的I/O時需要注意安排好它們讀和寫的次序,有可能在某些情況下需要用到雙線程,一個處理寫,另一個處理讀。
在Eclipse這些調試工具中可以在Debug視圖中找出你懷疑的線程的名字,右擊它選Suspend,這時它會顯示出這個線程的當前的StackTrace,從中能看出這個線程當前執行到什麼位置,當你的is讀取的時候卡住了,你可以看對方寫入的程序的當前的StackTrace,看它在這一時刻它在干什麼,這樣就能找出為什麼對方沒有寫完它的內容導致你無法讀取完成的原因。
如圖:
❻ java socket長連接循環讀取數據
AIO和BIO了解一下
❼ java socket類實現在客戶端讀取來自伺服器的普通文本
給你一個聊天的客戶端,希望有用
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class client {
private String over;
private Socket socket;
private DataInputStream in;
public void connect() {
try {
socket = new Socket("192.168.1.101", 9888);
in = new DataInputStream(socket.getInputStream());
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
newThread th = new newThread();
Scanner can = new Scanner(System.in);th.start();
over = "";
while (!.equals("exit")) {
System.out.println("請輸入聊天內容");
String str = can.next();
os.writeUTF(str);
over = str;
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[]) {
new client().connect();
}
class newThread extends Thread {
public void run() {
try {
while (!over.equals("exit")) {
String str = in.readUTF();
System.out.println(str);
over = str;
sleep(1000);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}