導航:首頁 > 編程語言 > javatcpsocket非同步

javatcpsocket非同步

發布時間:2023-07-05 04:08:15

java Socket開發 關於報文傳遞和接收

看 Oracle 官方教程,同步式的 Socket 就是傳統的一問一答方式,它就是你需要的。

客戶端先 socket.getOutputStream().write(...); 之後到 socket.getInputStream().read(byte[]) 在循環中讀取直到 read 方法返回 -1 或你期望的位元組數已經全部收到了就停下來,如果不嘗試停下來,後面的 read 將會阻塞等待。


http://docs.oracle.com/javase/tutorial/networking/sockets/index.html


基於性能改進,一般我們需要使用 NIO 非同步的 socket,只需要一個線程負責通信,每個線程都有自己的出站消息隊列和入站消息隊列,以線程為 key 區分開,通信線程只負責把各自的消息從出站隊列中發送去並把收到的消息放入入站隊列中,應用程序線程就去各自的消息隊列中取消息就可以了。因為每個應用線程有各自的消息隊列,我們把消息放入出站隊列之後就到入站隊列上用同步鎖等待的方法阻塞到有消息回答時為止。


關於 NIO non-blocking 非阻塞式 socket,下面有一個 NBTimeServer 例子,它講的是服務端。客戶端與此類似,

http://docs.oracle.com/javase/7/docs/technotes/guides/io/example/index.html


NIO 通信線程樣例。

publicvoidrun()
{
inttip=0;
try
{
selector=Selector.open();
SelectionKeyk=channel.register(selector,getInterestOptions());
k.attach(thread);//把當前線程綁定到附件中。

this.running=true;
statusChanged(Status.CONNECTED);
while(this.isRunning())
{
//select()isablockingoperation.
inteventCount=selector.select();
debug("[MC.Debug]PollingTCPevents..."+eventCount);
if(eventCount>0&&channel.isOpen()&&this.isRunning())
{
Setkeys=selector.selectedKeys();
for(Iteratoriter=keys.iterator();iter.hasNext();iter.remove())
{
SelectionKeykey=(SelectionKey)iter.next();
Threadthread=(Thread)key.attachment();

if(!key.isValid())
{//channelisclosing.
break;
}
process(key);//處理讀取消息並把消息放入thread對應的隊列。//寫出消息類似的,不過在register時需要注冊寫出允許的事件,

}
}
}
}

⑵ JAVA Socket 底層是怎樣基於TCP/IP 實現的

首先必須明確:TCP/IP模型中有四層結構: 應用層(Application Layer)、傳輸層(Transport Layer)、網路層(Internet Layer
)、鏈路層(LinkLayer)
其中Ip協議(Internet Protocol)是位於網路層的,TCP協議時位於傳輸層的。通過Ip協議可以使可以使兩台計算機使用同一種語言,從而允許Internet上連接不同類型的計算機和不同操作系統的網路。Ip協議只保證計算機能夠接收和發送分組數據。當計算機要和遠程的計算機建立連接時,TCP協議會讓他們建立連接:用於發送和接收數據的虛擬電路。

套接字或插座(socket)是一種軟體形式的抽象,用於表達兩台機器間一個連接的「終端」。針對一個特定的連接,每台機器上都有一個「套接字」,可以想像它們之間有一條虛擬的「線纜」。JAVA
有兩個基於數據流的套接字類:ServerSocket,伺服器用它「偵聽」進入的連接;Socket,客戶端用它初始一次連接。偵聽套接字只能接收新的連接請求,不能接收實際的數據包,即ServerSocket不能接收實際的數據包。
套接字是基於TCP/IP實現的,它是用來提供一個訪問TCP的服務介面,或者說套接字socket是TCP的應用編程介面API,通過它應用層就可以訪問TCP提供的服務。
在JAVA中,我們用 ServerSocket、Socket類創建一個套接字連接,從套接字得到的結果是一個InputStream以及OutputStream對象,以便將連接作為一個IO流對象對待。通過IO流可以從流中讀取數據或者寫數據到流中,讀寫IO流會有異常IOException產生。

⑶ 求大神點撥:「Java Socket」編程採用TCP協議是否能夠在一個線程里寫出多

Socket,又稱為套接字,Socket是計算機網路派枝通信的基本的技術之一。如今大多數基於網路的軟體,如瀏覽器,即時通訊工具甚至是P2P下載都是基於Socket實現的。本文仿羨慧會介紹一下基於TCP/IP的Socket編程,並且如何寫一個客戶端/伺服器程序。
方法/步驟

Java中的socket編程 下面的部分將通過一些示例講解一下如何使用socket編寫客戶端和伺服器端的程序。 注意:在接下來的示例中,我將使用基於TCP/IP協議的socket編程,因為這個協議遠遠比UDP/IP使用的要廣泛。並且所有的socket相關的類都位於java.net包備答下,所以在我們進行socket編程時需要引入這個包。

寫入數據 接下來就是寫入請求數據,我們從客戶端的socket對象中得到OutputStream對象,然後寫入數據後。很類似文件IO的處理代碼

打開伺服器端的socket

讀取數據 通過上面得到的socket對象獲取InputStream對象,然後安裝文件IO一樣讀取數據即可。這里我們將內容列印出來。

使用socket實現一個回聲伺服器,就是伺服器會將客戶端發送過來的數據傳回給客戶端。

⑷ 用java編寫一個能進行簡單TCP/IP通信的C/S程序

import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer
{
public static void main(String[] args) throws Exception
{
// 創建伺服器端的socket對象
ServerSocket ss = new ServerSocket(5000);

// 監聽連接
Socket socket = ss.accept();
// 直到連接建立好之後代碼才會往下執行

System.out.println("Connected Successfully!");

}

}

import java.net.Socket;

public class TcpClient
{
public static void main(String[] args) throws Exception
{
Socket socket = new Socket("127.0.0.1", 5000);
}

}

⑸ 關於socket非同步和同步通信的區別

socket傳輸中拿tcp傳輸為例。假設伺服器a
客戶機b進行通信傳輸。首先需要在a機建立監聽線程。監聽某一埠,那麼b機可以向a機發送通訊請求,b機連接到a機以後。a機可以從他的監聽隊列中取的一個監聽對象。在a端拿到了這個socket對象就可以進行接收跟發送數據了。這里問題就出現了。假如b端在請求a端的時候請求成功就發送一條數據。那麼
a端就可以直接拿socket對象得到他的信息。但是假如b端並沒有在連接成功後直接發送信息而是在後來不確定的時間這內發送的信息。那麼a端就無法得到這條信息。通常的做法是用一個定時器去不短的掃描這個數據緩存區。看是不是有數據存在這樣效率非常低下。那麼如何解決這個問題呢。就用到了我們的非同步傳輸。非同步傳輸的原理是。在a端得到這個socket對象以後並不是直接去接收數據而是建立一個回調函數。回調函數是由系統維護的。他在指定的時間自動去掃描數據存儲區。假如有數據他就把數據存儲到指定的位元組數組中。不用用戶自己去關心。
那麼同步與非同步分別應用於什麼情況呢?假如用戶的socket連接數據比較短暫的。一次連接直接發送數據的或客戶端比較少的就使用同步假如用戶的socket屬於長時間連接的就使用非同步方式

⑹ socket實現過程,具體用的方法;怎麼實現非同步socket

基於C#的socket編程的TCP非同步實現
一、摘要
本篇博文闡述基於TCP通信協議的非同步實現。

二、實驗平台
Visual Studio 2010

三、非同步通信實現原理及常用方法
3.1 建立連接
在同步模式中,在伺服器上使用Accept方法接入連接請求,而在客戶端則使用Connect方法來連接伺服器。相對地,在非同步模式下,伺服器可以使用BeginAccept方法和EndAccept方法來完成連接到客戶端的任務,在客戶端則通過BeginConnect方法和EndConnect方法來實現與伺服器的連接。

BeginAccept在非同步方式下傳入的連接嘗試,它允許其他動作而不必等待連接建立才繼續執行後面程序。在調用BeginAccept之前,必須使用Listen方法來偵聽是否有連接請求,BeginAccept的函數原型為:

BeginAccept(AsyncCallback AsyncCallback, Ojbect state)
參數:

AsyncCallBack:代表回調函數

state:表示狀態信息,必須保證state中包含socket的句柄

使用BeginAccept的基本流程是:
(1)創建本地終節點,並新建套接字與本地終節點進行綁定;
(2)在埠上偵聽是否有新的連接請求;
(3)請求開始接入新的連接,傳入Socket的實例或者StateOjbect的實例。

參考代碼:

復制代碼
//定義IP地址
IPAddress local = IPAddress.Parse("127.0,0,1");
IPEndPoint iep = new IPEndPoint(local,13000);
//創建伺服器的socket對象
Socket server = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
server.Bind(iep);
server.Listen(20);
server.BeginAccecpt(new AsyncCallback(Accept),server);
復制代碼
當BeginAccept()方法調用結束後,一旦新的連接發生,將調用回調函數,而該回調函數必須包括用來結束接入連接操作的EndAccept()方法。

該方法參數列表為 Socket EndAccept(IAsyncResult iar)

下面為回調函數的實例:

復制代碼
void Accept(IAsyncResult iar)
{
//還原傳入的原始套接字
Socket MyServer = (Socket)iar.AsyncState;
//在原始套接字上調用EndAccept方法,返回新的套接字
Socket service = MyServer.EndAccept(iar);
}
復制代碼
至此,伺服器端已經准備好了。客戶端應通過BeginConnect方法和EndConnect來遠程連接主機。在調用BeginConnect方法時必須注冊相應的回調函數並且至少傳遞一個Socket的實例給state參數,以保證EndConnect方法中能使用原始的套接字。下面是一段是BeginConnect的調用:

Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp)
IPAddress ip=IPAddress.Parse("127.0.0.1");
IPEndPoint iep=new IPEndPoint(ip,13000);
socket.BeginConnect(iep, new AsyncCallback(Connect),socket);
EndConnect是一種阻塞方法,用於完成BeginConnect方法的非同步連接誒遠程主機的請求。在注冊了回調函數後必須接收BeginConnect方法返回的IASynccReuslt作為參數。下面為代碼演示:

復制代碼
void Connect(IAsyncResult iar)
{
Socket client=(Socket)iar.AsyncState;
try
{
client.EndConnect(iar);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{

}
}
復制代碼

除了採用上述方法建立連接之後,也可以採用TcpListener類裡面的方法進行連接建立。下面是伺服器端對關於TcpListener類使用BeginAccetpTcpClient方法處理一個傳入的連接嘗試。以下是使用BeginAccetpTcpClient方法和EndAccetpTcpClient方法的代碼:

復制代碼
public static void DoBeginAccept(TcpListener listner)
{
//開始從客戶端監聽連接
Console.WriteLine("Waitting for a connection");
//接收連接
//開始准備接入新的連接,一旦有新連接嘗試則調用回調函數DoAcceptTcpCliet
listner.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpCliet), listner);
}

//處理客戶端的連接
public static void DoAcceptTcpCliet(IAsyncResult iar)
{
//還原原始的TcpListner對象
TcpListener listener = (TcpListener)iar.AsyncState;

//完成連接的動作,並返回新的TcpClient
TcpClient client = listener.EndAcceptTcpClient(iar);
Console.WriteLine("連接成功");
}
復制代碼
代碼的處理邏輯為:
(1)調用BeginAccetpTcpClient方法開開始連接新的連接,當連接視圖發生時,回調函數被調用以完成連接操作;
(2)上面DoAcceptTcpCliet方法通過AsyncState屬性獲得由BeginAcceptTcpClient傳入的listner實例;
(3)在得到listener對象後,用它調用EndAcceptTcpClient方法,該方法返回新的包含客戶端信息的TcpClient。

BeginConnect方法和EndConnect方法可用於客戶端嘗試建立與服務端的連接,這里和第一種方法並無區別。下面看實例:

復制代碼
public void doBeginConnect(IAsyncResult iar)
{
Socket client=(Socket)iar.AsyncState;
//開始與遠程主機進行連接
client.BeginConnect(serverIP[0],13000,requestCallBack,client);
Console.WriteLine("開始與伺服器進行連接");
}
private void requestCallBack(IAsyncResult iar)
{
try
{
//還原原始的TcpClient對象
TcpClient client=(TcpClient)iar.AsyncState;
//
client.EndConnect(iar);
Console.WriteLine("與伺服器{0}連接成功",client.Client.RemoteEndPoint);
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{

}
}
復制代碼
以上是建立連接的兩種方法。可根據需要選擇使用。

3.2 發送與接受數據
在建立了套接字的連接後,就可以伺服器端和客戶端之間進行數據通信了。非同步套接字用BeginSend和EndSend方法來負責數據的發送。注意在調用BeginSend方法前要確保雙方都已經建立連接,否則會出異常。下面演示代碼:

復制代碼
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
復制代碼
接收數據是通過BeginReceive和EndReceive方法:

復制代碼
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.

state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
復制代碼
上述代碼的處理邏輯為:

(1)首先處理連接的回調函數里得到的通訊套接字client,接著開始接收數據;
(2)當數據發送到緩沖區中,BeginReceive方法試圖從buffer數組中讀取長度為buffer.length的數據塊,並返回接收到的數據量bytesRead。最後接收並列印數據。除了上述方法外,還可以使用基於NetworkStream相關的非同步發送和接收方法,下面是基於NetworkStream相關的非同步發送和接收方法的使用介紹。
NetworkStream使用BeginRead和EndRead方法進行讀操作,使用BeginWreite和EndWrete方法進行寫操作,下面看實例:

復制代碼
static void DataHandle(TcpClient client)
{
TcpClient tcpClient = client;
//使用TcpClient的GetStream方法獲取網路流
NetworkStream ns = tcpClient.GetStream();
//檢查網路流是否可讀
if(ns.CanRead)
{
//定義緩沖區
byte[] read = new byte[1024];
ns.BeginRead(read,0,read.Length,new AsyncCallback(myReadCallBack),ns);
}
else
{
Console.WriteLine("無法從網路中讀取流數據");
}
}

public static void myReadCallBack(IAsyncResult iar)
{
NetworkStream ns = (NetworkStream)iar.AsyncState;
byte[] read = new byte[1024];
String data = "";
int recv;

recv = ns.EndRead(iar);
data = String.Concat(data, Encoding.ASCII.GetString(read, 0, recv));

//接收到的消息長度可能大於緩沖區總大小,反復循環直到讀完為止
while (ns.DataAvailable)
{
ns.BeginRead(read, 0, read.Length, new AsyncCallback(myReadCallBack), ns);
}
//列印
Console.WriteLine("您收到的信息是" + data);
}
復制代碼
3.3 程序阻塞與非同步中的同步問題
.Net里提供了EventWaitHandle類來表示一個線程的同步事件。EventWaitHandle即事件等待句柄,他允許線程通過操作系統互發信號和等待彼此的信號來達到線程同步的目的。這個類有2個子類,分別為AutoRestEevnt(自動重置)和ManualRestEvent(手動重置)。下面是線程同步的幾個方法:
(1)Rset方法:將事件狀態設為非終止狀態,導致線程阻塞。這里的線程阻塞是指允許其他需要等待的線程進行阻塞即讓含WaitOne()方法的線程阻塞;
(2)Set方法:將事件狀態設為終止狀態,允許一個或多個等待線程繼續。該方法發送一個信號給操作系統,讓處於等待的某個線程從阻塞狀態轉換為繼續運行,即WaitOne方法的線程不在阻塞;
(3)WaitOne方法:阻塞當前線程,直到當前的等待句柄收到信號。此方法將一直使本線程處於阻塞狀態直到收到信號為止,即當其他非阻塞進程調用set方法時可以繼續執行。

復制代碼
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
//IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
//IPAddress ipAddress = ipHostInfo.AddressList[0];
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local
//endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
復制代碼

上述代碼的邏輯為:

(1)試用了ManualRestEvent對象創建一個等待句柄,在調用BeginAccept方法前使用Rest方法允許其他線程阻塞;
(2)為了防止在連接完成之前對套接字進行讀寫操作,務必要在BeginAccept方法後調用WaitOne來讓線程進入阻塞狀態。

當有連接接入後系統會自動調用會調用回調函數,所以當代碼執行到回調函數時說明連接已經成功,並在函數的第一句就調用Set方法讓處於等待的線程可以繼續執行

閱讀全文

與javatcpsocket非同步相關的資料

熱點內容
逍遙安卓微信驗證 瀏覽:579
5g網路什麼時候普及河北邢台 瀏覽:709
編程和運營哪個更適合創業 瀏覽:893
尤里x怎麼升級 瀏覽:399
做業務績效考核需要哪些數據 瀏覽:433
dnf85版本劍魔刷圖加點 瀏覽:407
手機硬碟測試架可以讀取哪些數據 瀏覽:704
ug前後處理結算結果找不到文件 瀏覽:769
網頁框架拆分代碼 瀏覽:382
未來十年網路安全有什麼影響 瀏覽:362
win10更新後進不了劍靈 瀏覽:243
iphone471激活出錯 瀏覽:648
怎麼把文件拷到u盤 瀏覽:620
中伊簽署文件視頻 瀏覽:661
電信光寬頻網路不穩定 瀏覽:504
網路崗軟路由 瀏覽:995
黑莓z10在哪裡下載app 瀏覽:310
net批量下載文件 瀏覽:696
怎麼把蘋果一體機文件拷貝 瀏覽:117
sql文件怎麼寫 瀏覽:9

友情鏈接