當前位置:首頁 » 編程軟體 » socket非同步編程

socket非同步編程

發布時間: 2023-08-22 15:26:50

1. java 非同步編程

用非同步輸入輸出流編寫Socket進程通信程序
在Merlin中加入了用於實現非同步輸入輸出機制的應用程序介麵包:java.nio(新的輸入輸出包,定義了很多基本類型緩沖(Buffer)),java.nio.channels(通道及選擇器等,用於非同步輸入輸出),java.nio.charset(字元的編碼解碼)。通道(Channel)首先在選擇器(Selector)中注冊自己感興趣的事件,當相應的事件發生時,選擇器便通過選擇鍵(SelectionKey)通知已注冊的通道。然後通道將需要處理的信息,通過緩沖(Buffer)打包,編碼/解碼,完成輸入輸出控制。

通道介紹:
這里主要介紹ServerSocketChannel和 SocketChannel.它們都是可選擇的(selectable)通道,分別可以工作在同步和非同步兩種方式下(注意,這里的可選擇不是指可以選擇兩種工作方式,而是指可以有選擇的注冊自己感興趣的事件)。可以用channel.configureBlocking(Boolean )來設置其工作方式。與以前版本的API相比較,ServerSocketChannel就相當於ServerSocket(ServerSocketChannel封裝了ServerSocket),而SocketChannel就相當於Socket(SocketChannel封裝了Socket)。當通道工作在同步方式時,編程方法與以前的基本相似,這里主要介紹非同步工作方式。

所謂非同步輸入輸出機制,是指在進行輸入輸出處理時,不必等到輸入輸出處理完畢才返回。所以非同步的同義語是非阻塞(None Blocking)。在伺服器端,ServerSocketChannel通過靜態函數open()返回一個實例serverChl。然後該通道調用serverChl.socket().bind()綁定到伺服器某埠,並調用register(Selector sel, SelectionKey.OP_ACCEPT)注冊OP_ACCEPT事件到一個選擇器中(ServerSocketChannel只可以注冊OP_ACCEPT事件)。當有客戶請求連接時,選擇器就會通知該通道有客戶連接請求,就可以進行相應的輸入輸出控制了;在客戶端,clientChl實例注冊自己感興趣的事件後(可以是OP_CONNECT,OP_READ,OP_WRITE的組合),調用clientChl.connect(InetSocketAddress )連接伺服器然後進行相應處理。注意,這里的連接是非同步的,即會立即返回而繼續執行後面的代碼。

選擇器和選擇鍵介紹:
選擇器(Selector)的作用是:將通道感興趣的事件放入隊列中,而不是馬上提交給應用程序,等已注冊的通道自己來請求處理這些事件。換句話說,就是選擇器將會隨時報告已經准備好了的通道,而且是按照先進先出的順序。那麼,選擇器是通過什麼來報告的呢?選擇鍵(SelectionKey)。選擇鍵的作用就是表明哪個通道已經做好了准備,准備干什麼。你也許馬上會想到,那一定是已注冊的通道感興趣的事件。不錯,例如對於伺服器端serverChl來說,可以調用key.isAcceptable()來通知serverChl有客戶端連接請求。相應的函數還有:SelectionKey.isReadable(),SelectionKey.isWritable()。一般的,在一個循環中輪詢感興趣的事件(具體可參照下面的代碼)。如果選擇器中尚無通道已注冊事件發生,調用Selector.select()將阻塞,直到有事件發生為止。另外,可以調用selectNow()或者select(long timeout)。前者立即返回,沒有事件時返回0值;後者等待timeout時間後返回。一個選擇器最多可以同時被63個通道一起注冊使用。
應用實例:
下面是用非同步輸入輸出機制實現的客戶/伺服器實常式序――程序清單1(限於篇幅,只給出了伺服器端實現,讀者可以參照著實現客戶端代碼):

程序類圖

public class NBlockingServer {
int port = 8000;
int BUFFERSIZE = 1024;
Selector selector = null;
ServerSocketChannel serverChannel = null;
HashMap clientChannelMap = null;//用來存放每一個客戶連接對應的套接字和通道

public NBlockingServer( int port ) {
this.clientChannelMap = new HashMap();
this.port = port;
}

public void initialize() throws IOException {
//初始化,分別實例化一個選擇器,一個伺服器端可選擇通道
this.selector = Selector.open();
this.serverChannel = ServerSocketChannel.open();
this.serverChannel.configureBlocking(false);
InetAddress localhost = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(localhost, this.port );
this.serverChannel.socket().bind(isa);//將該套接字綁定到伺服器某一可用埠
}
//結束時釋放資源
public void finalize() throws IOException {
this.serverChannel.close();
this.selector.close();
}
//將讀入位元組緩沖的信息解碼
public String decode( ByteBuffer byteBuffer ) throws
CharacterCodingException {
Charset charset = Charset.forName( "ISO-8859-1" );
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode( byteBuffer );
String result = charBuffer.toString();
return result;
}
//監聽埠,當通道准備好時進行相應操作
public void portListening() throws IOException, InterruptedException {
//伺服器端通道注冊OP_ACCEPT事件
SelectionKey acceptKey =this.serverChannel.register( this.selector,
SelectionKey.OP_ACCEPT );
//當有已注冊的事件發生時,select()返回值將大於0
while (acceptKey.selector().select() > 0 ) {
System.out.println("event happened");
//取得所有已經准備好的所有選擇鍵
Set readyKeys = this.selector.selectedKeys();
//使用迭代器對選擇鍵進行輪詢
Iterator i = readyKeys.iterator();
while (i
else if ( key.isReadable() ) {//如果是通道讀准備好事件
System.out.println("Readable");
//取得選擇鍵對應的通道和套接字
SelectableChannel nextReady =
(SelectableChannel) key.channel();
Socket socket = (Socket) key.attachment();
//處理該事件,處理方法已封裝在類ClientChInstance中
this.readFromChannel( socket.getChannel(),
(ClientChInstance)
this.clientChannelMap.get( socket ) );
}
else if ( key.isWritable() ) {//如果是通道寫准備好事件
System.out.println("writeable");
//取得套接字後處理,方法同上
Socket socket = (Socket) key.attachment();
SocketChannel channel = (SocketChannel)
socket.getChannel();
this.writeToChannel( channel,"This is from server!");
}
}
}
}
//對通道的寫操作
public void writeToChannel( SocketChannel channel, String message )
throws IOException {
ByteBuffer buf = ByteBuffer.wrap( message.getBytes() );
int nbytes = channel.write( buf );
}
//對通道的讀操作
public void readFromChannel( SocketChannel channel, ClientChInstance clientInstance )
throws IOException, InterruptedException {
ByteBuffer byteBuffer = ByteBuffer.allocate( BUFFERSIZE );
int nbytes = channel.read( byteBuffer );
byteBuffer.flip();
String result = this.decode( byteBuffer );
//當客戶端發出」@exit」退出命令時,關閉其通道
if ( result.indexOf( "@exit" ) >= 0 ) {
channel.close();
}
else {
clientInstance.append( result.toString() );
//讀入一行完畢,執行相應操作
if ( result.indexOf( "\n" ) >= 0 ){
System.out.println("client input"+result);
clientInstance.execute();
}
}
}
//該類封裝了怎樣對客戶端的通道進行操作,具體實現可以通過重載execute()方法
public class ClientChInstance {
SocketChannel channel;
StringBuffer buffer=new StringBuffer();
public ClientChInstance( SocketChannel channel ) {
this.channel = channel;
}
public void execute() throws IOException {
String message = "This is response after reading from channel!";
writeToChannel( this.channel, message );
buffer = new StringBuffer();
}
//當一行沒有結束時,將當前字竄置於緩沖尾
public void append( String values ) {
buffer.append( values );
}
}

//主程序
public static void main( String[] args ) {
NBlockingServer nbServer = new NBlockingServer(8000);
try {
nbServer.initialize();
} catch ( Exception e ) {
e.printStackTrace();
System.exit( -1 );
}
try {
nbServer.portListening();
}
catch ( Exception e ) {
e.printStackTrace();
}
}
}

程序清單1

小結:
從以上程序段可以看出,伺服器端沒有引入多餘線程就完成了多客戶的客戶/伺服器模式。該程序中使用了回調模式(CALLBACK)。需要注意的是,請不要將原來的輸入輸出包與新加入的輸入輸出包混用,因為出於一些原因的考慮,這兩個包並不兼容。即使用通道時請使用緩沖完成輸入輸出控制。該程序在Windows2000,J2SE1.4下,用telnet測試成功。

2. python非同步網路編程怎麼使socket關閉之後立即執行一段代碼

自己實現MySocket類,繼承自socket,然後重寫它的close方法,在裡面調用父類close方法,再加上你自己想做的工作,其他不要動。

3. java開發聊天功能用什麼技術比較好


開發聊天功能可以採用以下幾種技術:

  • Socket編程:使用Java Socket編程可以實現基於TCP或UDP的網路通信,這虧畢是Java最基礎、最底層的網路編程技術。使用Socket編程可以實現實時通信、消息推送等功能,但需要自己實現消息協議、數據傳輸等細節。

  • Java NIO:Java NIO(New IO)是Java 1.4之後引入的一種新IO API,它提供了基於事件驅動的非同步IO操作,可以大大提高網路通信效率。使用Java NIO可以實現高並發、高性能的網路通信,但需要掌握NIO的相關概念和使用方式。

  • WebSockets:WebSockets是HTML5標准中新增的一種協議,可以實現基於瀏覽器的實時雙向通信。使用Java開發WebSockets可以實現跨平台、跨瀏覽器的聊天功能,但需要掌握WebSocket協議的相關概念和使用方式。

  • 第三方庫:Java中有許多第三方庫可以用於實現聊天功能,如Netty、Apache MINA、Smack等。這些庫提供了更加簡銷悉芹單、易用的API,可以快速陸升搭建聊天功能,但需要熟悉相關庫的使用方法和特性。

  • 具體選用哪種技術,需要根據具體需求、開發經驗和技術水平等因素進行綜合考慮。

4. 關於c#的Socket非同步網路編程問題

這樣的寫法有點問題:

1)伺服器端既然採用了非同步方式Accept,就沒有必要再啟線程

2)估計allDone是一個ManualResetEvent。用ManualResetEvent的目的什麼呢?

伺服器端採用非同步Accept的代碼其實很簡單,也不需要ManualResetEvent同步

publicclassAppTCPServer
{
publicAppTCPServer(stringlocalIP,intport)
{
Socketsocket=newSocket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
EndPointlocalEP=newIPEndPoint(IPAddress.Parse(localIP),port);
socket.Bind(localEP);
socket.Listen(100);
socket.BeginAccept(AcceptAsync,socket);
}

privatevoidAcceptAsync(IAsyncResultar)
{
Socketsocket=ar.AsyncStateasSocket;
try
{
Socketclient=socket.EndAccept(ar);
Console.WriteLine("客戶端連接成功!客戶端:{0}",client.RemoteEndPoint.ToString());
if(OnConnected!=null)
{
OnConnected(this,newClientConnectedEventArgs(client));
}
}
catch(Exceptione)
{
Console.WriteLine("AcceptAsync發生異常,異常信息: {0}",e.Message);
}
finally
{
//繼續非同步Accept
socket.BeginAccept(AcceptAsync,socket);
謹賀}
}

//客戶端連接後的事件OnConnect
publiceventEventHandler<ClientConnectedEventArgs>OnConnected;
}

///<summary>
///事件參數:接收客戶端連接後的事件參數
///</summary>
:EventArgs
答雹{
(SocketclientSocket)
{
ClientSocket=clientSocket;
}
publicSocketClientSocket{get;privateset;}
}

classProgram
{
staticvoidMain(string[]args)
{
祥舉派AppTCPServerserver=newAppTCPServer("127.0.0.01",8000);
server.OnConnected+=server_OnConnected;
Console.WriteLine("按任意鍵結束程序……");
Console.ReadKey();
}

staticvoidserver_OnConnected(objectsender,ClientConnectedEventArgse)
{
Socketclient=e.ClientSocket;
stringhello="HellofromAppTCPServer";
client.Send(Encoding.Default.GetBytes(hello));
}
}

客戶端測試程序

classProgram
{
staticvoidMain(string[]args)
{
//模擬100個客戶連接伺服器
for(inti=0;i<100;i++)
{
Socketsocket=ConnectToServer("127.0.0.1",8000);
byte[]buffer=newbyte[1024];
intbytesRecevied=socket.Receive(buffer,buffer.Length,SocketFlags.None);
byte[]messageBytes=newbyte[bytesRecevied];
Array.Copy(buffer,messageBytes,bytesRecevied);
Console.WriteLine(Encoding.Default.GetString(messageBytes));
socket.Disconnect(false);
socket.Close();
}
Console.ReadKey();staticSocketConnectToServer(stringserverIP,intserverPort)
{
Socketsocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
EndPointlocalEP=newIPEndPoint(IPAddress.Any,0);
socket.Bind(localEP);
socket.Connect(newIPEndPoint(IPAddress.Parse(serverIP),serverPort));
returnsocket;
}
}
熱點內容
手機wps密碼怎麼取消密碼 發布:2025-02-04 00:51:44 瀏覽:593
演算法邏輯表 發布:2025-02-04 00:51:44 瀏覽:238
零售股票如何配置主線 發布:2025-02-04 00:51:07 瀏覽:945
預演算法施行時間是 發布:2025-02-04 00:50:30 瀏覽:339
世界ol上傳照片 發布:2025-02-04 00:34:13 瀏覽:60
有初始化的數組編譯提示重復定義 發布:2025-02-04 00:33:21 瀏覽:583
家裡電腦wifi密碼怎麼改 發布:2025-02-04 00:27:35 瀏覽:409
手機網頁緩存視頻 發布:2025-02-03 23:38:48 瀏覽:835
agnes演算法 發布:2025-02-03 23:38:05 瀏覽:38
私密上傳在哪 發布:2025-02-03 23:33:04 瀏覽:1005