AS3 Socket從零開始。

最近項目到有點緊,有點對不住大家,今天在這裏寫點小知識算是向大家道歉!並祝大家在新的一年裏有更大的收穫!--FL狂人
大家如果想學AS3 Socket直接在百度裏搜一下,會找到很多AS3與Java服務器的例子,很多朋友也許看得很糊塗,也有很多朋友看懂了,但想學更進一步的學習卻又不好找教程了。這裏我對網上常見的一個例子加點註釋,並在原有的基礎上加一些改動。轉載請註明文章來自Aizna開源社區http://www.aizna.com/
先附上網上找的AS3客戶端代碼:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
import flash.utils.ByteArray; public class SocketExample extends Sprite
{ // The state constants to describe the protocol
public const DETERMINE_VERSION:int = 0;
public const RECEIVE_CHALLENGE:int = 1;
public const NORMAL:int = 2;
public const PORT:int = 5678; // Maps a state to a processing function
private var stateMap:Object; // Keeps track of the current protocol state
private var currentState:int; private var socket:Socket; public function SocketExample( )
{
// Initialzes the states map
stateMap = new Object( );
stateMap[DETERMINE_VERSION] = readVersion;
stateMap[RECEIVE_CHALLENGE] = readChallenge;
stateMap[NORMAL] = readNormalProtocol; // Initialze the current state
currentState = DETERMINE_VERSION; // Create and connect the socket
socket = new Socket( );
socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData );
socket.addEventListener( Event.CONNECT, onConnect );
btnSend.label = "Send Data";
btnSend.emphasized = true;
btnSend.width = 150;
btnSend.move(20, 20);
//addChild(btnSend); btnSend.addEventListener(MouseEvent.CLICK, sendData);
} private function sendData( event:Event )
{ if (! socket.connected)
{
// Connect to the server
socket.connect( "localhost", PORT );
} trace("send...");
socket.writeUTFBytes("example\n");
socket.flush(); } private function onConnect(event:Event):void
{
trace( "The socket is now connected..." ); } private function onSocketData( eventrogressEvent ):void
{
trace( "Socket received " + socket.bytesAvailable + " byte(s) of data:" );
//trace(socket.readMultiByte(socket.bytesAvailable, "UTF-8"));

// Look up the processing function based on the current state
var processFunc:Function = stateMap[currentState];
processFunc( );
} private function readVersion( ):void
{
// Step 1 - read the version from the server
var version:int = socket.readInt(); // Once the version is read, the next state is receiving
// the challenge from the server
currentState = RECEIVE_CHALLENGE; // Step 2 - write the version back to the server
socket.writeInt( version );
socket.flush( );
} private function readChallenge( ):void
{
// Step 3 - read the 8 byte challenge into a byte array
var bytes:ByteArray = new ByteArray( );
socket.readBytes( bytes, 0, 8 ); // After the challenge is received, the next state is
// the normal protocol operation
currentState = NORMAL; // Step 4 - write the bytes back to the server
socket.writeBytes( bytes );
socket.flush( );
}

private function readMultiByte( ):void
{
socket.readMultiByte(socket.bytesAvailable, "UTF-8");
} private function readNormalProtocol( ):void
{
// Step 5 - process the normal socket messages here now that
// that handshaking process is complete
}
}
}

java 服務端代碼
import java.io.*;
import java.net.*;
public class SocketSever {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678); while (true) {
Socket client=server.accept();
BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out=new PrintWriter(client.getOutputStream());
//while(true){
String str=in.readLine();
System.out.println(str);
out.println("has receive….");
out.flush();
if("end".equals(str))
break;
//}
client.close();
}
}
}
 
 
測試的時候flash得先從組件里拉一個Button組件到舞臺上,並取個實例名btnSend,然後先運行java服務端,再啓動客戶端,點擊按鈕就會看到連接成功的輸出。
上面的代碼顯得有點亂,如果看不懂沒關係,我們把上面的代碼精簡一下。
首先是AS3
如果我們要用Socket,得先導入import flash.net.Socket;這個包。如果我們把這個類當文檔類來使用的話,需要導入import flash.display.Sprite;這個包。最後我們得是否連接成功這個事件,還得導入import flash.events.*;這個包。
所以代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
public class Main
{ public function Main()
{
// constructor code
}
}
}
http://www.shengshiyouxi.com
第二步,我們需要建立一個Socket並作初始化,然後連接到服務器。加上上面的代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
public class Main extends Sprite
{
private var socket:Socket;
public function Main()
{
socket = new Socket();
socket.connect( "localhost", 5678);
}
}
}

對應的Java服務端代碼:
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678);//建立一個Socket服務端。
server.accept();//等待客戶端連接,如果沒有客戶端連接,
//程序會停在此行,而不會執行下一行。
System.out.println("客戶端已連接!");//當有客戶端連接上來的時候,
//打印輸出客戶端已連接。
}
}

以上代碼可以說是最簡單的Socket連接。
 
 
到這裏,服務端代碼暫時不管,先把給客戶端的Socket加上事件,所以我們在連接到服務器前先加上以下兩行代碼:
socket.addEventListener(Event.CONNECT, onSocketConnect);//偵聽Socket是否已連接上。
socket.addEventListener(Event.CLOSE, onSocketSeverClose);//偵聽服務器是否已關閉。
然後寫上事件的處理函數。
完整代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
public class Main extends Sprite
{
private var socket:Socket;
public function Main()
{
socket = new Socket();//新建一個Socket

socket.addEventListener(Event.CONNECT, onSocketConnect);//偵聽Socket是否已連接上。
socket.addEventListener(Event.CLOSE, onSocketSeverClose);//偵聽服務器是否已關閉。

socket.connect( "localhost", 5678);//連接到服務器
}

private function onSocketConnect(e:Event):void
{
trace("已連接上服務器!");
}

private function onSocketSeverClose(e:Event):void
{
trace("服務器已關閉!");
}
}
}
 
 
啓動服務端再測試下。發現我們剛連上服務器,服務器就關閉了。所以我們把服務端代碼也改一下。
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678);//建立一個Socket服務端。
while(true)
{
server.accept();//等待客戶端連接,如果沒有客戶端連接,程序會停在此行,而不會執行下一行。
System.out.println("客戶端已連接!");//當有客戶端連接上來的時候,打印輸出客戶端已連接。
}
}
}

這裏我只是在等待客戶端連接的地方加了個死循環,這們服務端不會在有客戶端連上來後自動關閉了,它會一直等等服務端的連接。大家可以再測試一下。
 
 
 
接下來,我們在連接服務器後,向服務器發送一個字符串。發送字符串會用到Socket的write方法和flush方法。write方法只是將要發送的信息存儲起來,但沒真正發送出去。而flush方法是將要發送的信息發送到數據流裏。完整代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
public class Main extends Sprite
{
private var socket:Socket;
public function Main()
{
socket = new Socket();//新建一個Socket

socket.addEventListener(Event.CONNECT, onSocketConnect);//偵聽Socket是否已連接上。
socket.addEventListener(Event.CLOSE, onSocketSeverClose);//偵聽服務器是否已關閉。

socket.connect( "localhost", 5678);//連接到服務器
}

private function onSocketConnect(e:Event):void
{
trace("已連接上服務器!");

//新加代碼
socket.writeUTFBytes("abc\n");
socket.flush();
//新加代碼

}

private function onSocketSeverClose(e:Event):void
{
trace("服務器已關閉!");
}
}
}
 
 
 
注意:發送的字符串必須加上\n不然服務端不能識別已輸入已結束,當然,這只是針對於下面我們下面寫的服務端代碼而言。
對應的服務端代碼如下:
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678);//建立一個Socket服務端。
while(true)
{

Socket client=server.accept();//等待客戶端連接,如果沒有客戶端連接,程序會停在此行,而不會執行下一行。
System.out.println("客戶端已連接!");//當有客戶端連接上來的時候,打印輸出客戶端已連接。
BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
String str=in.readLine();
System.out.println(str);
}
}
}
 
 
接下來,服務端收到客戶端發送的消息後也回一個字符串。有發就要有收,客戶端也得同步寫接收的語句。在此之前,先給客戶端添加一個收到信息的事件偵聽。
socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData );//偵聽服務端是否有消息發送過來。
然後寫上事件處理函數
private function onSocketData(e:Event):void
{
var str:String = socket.readMultiByte(socket.bytesAvailable, "UTF-8");
trace(str);
}

完整代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
public class Main extends Sprite
{
private var socket:Socket;
public function Main()
{
socket = new Socket();//新建一個Socket

socket.addEventListener(Event.CONNECT, onSocketConnect);//偵聽Socket是否已連接上。
socket.addEventListener(Event.CLOSE, onSocketSeverClose);//偵聽服務器是否已關閉。
socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData );//偵聽服務端是否有消息發送過來。

socket.connect( "localhost", 5678);//連接到服務器
}

private function onSocketConnect(e:Event):void
{
trace("已連接上服務器!");
socket.writeUTFBytes("abc\n");
socket.flush();
}

private function onSocketData(e:Event):void
{
var str:String = socket.readMultiByte(socket.bytesAvailable, "UTF-8");
trace(str);
}

private function onSocketSeverClose(e:Event):void
{
trace("服務器已關閉!");
}
}
}
 
 
 
 
對應的服務端代碼如下:
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678);//建立一個Socket服務端。
while(true)
{

Socket client=server.accept();//等待客戶端連接,如果沒有客戶端連接,程序會停在此行,而不會執行下一行。
System.out.println("客戶端已連接!");//當有客戶端連接上來的時候,打印輸出客戶端已連接。
BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
String str=in.readLine();
System.out.println(str);
PrintWriter out=new PrintWriter(client.getOutputStream());
out.println("cba");
out.flush();
}
}
}

小結:到這裏算是寫了一個簡單的Socket連接,並實現了收發功能,如果從來沒接觸過Socket的朋友可以從上面的實例中學習Socket,通過上面的小實例可以看出,客戶端和服務端必須保持一致,很多朋友學Socket的的難處就是不會寫服務端程序,所以寫出來的程序沒法測試。而去下別人寫好的服務端程序又沒看懂,不知道如何寫對應的客戶端,所以就停步不學了。這裏我建議有以上問題的朋友瞭解一下Java語言,學會自己學對應的服務端語言,Java語言和AS3差別不大,寫服務端也很簡單。相對來說要容易一些。

下面我們將上面的代碼再進行擴展,實現通過按鈕點擊才連接服務器,然後通過按鈕發送一個文本框裏的輸入的內容。算是一個聊天程序的粗雛形。在此之前希望還不太會的朋友多練習一下上面的代碼,並通過自己的方式去實習,然後自己思考一下。如何實現我們剛提到的功能。
 
 
 
 
先在客戶端加上兩個按鈕。並取個實例名btnConn和btnSend,然後在代碼裏添加按鈕的點擊事件,並且把socket的連接和發送消息寫到兩個按鈕的點擊事件處理函數裏。

完整代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var socket:Socket;
public function Main()
{
socket = new Socket();//新建一個Socket

socket.addEventListener(Event.CONNECT, onSocketConnect);//偵聽Socket是否已連接上。
socket.addEventListener(Event.CLOSE, onSocketSeverClose);//偵聽服務器是否已關閉。
socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData );//偵聽服務端是否有消息發送過來。

btnConn.addEventListener(MouseEvent.CLICK, onBtnConnClick);
btnSend.addEventListener(MouseEvent.CLICK, onBtnSendClick);
}

private function onBtnConnClick(e:MouseEvent):void
{
socket.connect( "localhost", 5678);//連接到服務器
}

private function onBtnSendClick(e:MouseEvent):void
{
socket.writeUTFBytes("abc\n");
socket.flush();
}

private function onSocketConnect(e:Event):void
{
trace("已連接上服務器!");
}

private function onSocketData(e:Event):void
{
var str:String = socket.readMultiByte(socket.bytesAvailable, "UTF-8");
trace(str);
}

private function onSocketSeverClose(e:Event):void
{
trace("服務器已關閉!");
}
}
}

服務端代碼不變,這時可以再測試一下。
 
 
 
注意:測試的時候一定要先連服務器,再發送數據,不然會出錯。如果我們要讓代碼更人性化一些,可以在發送數據的時候測試一下Socket是否已連接上,所以我們可以加個Boolean變量,來記錄Socket是否已連接。
完整代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var socket:Socket;
private var isConnect:Boolean = false;
public function Main()
{
socket = new Socket();//新建一個Socket socket.addEventListener(Event.CONNECT, onSocketConnect);
//偵聽Socket是否已連接上。;
socket.addEventListener(Event.CLOSE, onSocketSeverClose);
//偵聽服務器是否已關閉。;
socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData );
//偵聽服務端是否有消息發送過來。; btnConn.addEventListener(MouseEvent.CLICK, onBtnConnClick);
btnSend.addEventListener(MouseEvent.CLICK, onBtnSendClick);
} private function onBtnConnClick(e:MouseEvent):void
{
socket.connect( "localhost", 5678);//連接到服務器;
}

private function onBtnSendClick(e:MouseEvent):void
{
if (isConnect)
{
socket.writeUTFBytes("abc\n");
socket.flush();
}
else
{
trace("服務器沒接連或已斷開!")
}
} private function onSocketConnect(e:Event):void
{
trace("已連接上服務器!");
isConnect = true;
} private function onSocketData(e:Event):void
{
var str:String = socket.readMultiByte(socket.bytesAvailable,"UTF-8");
trace(str);
} private function onSocketSeverClose(e:Event):void
{
trace("服務器已關閉!");
isConnect = false;
}
}
}
 
 
 
現在我們再加兩個文本框,一個用於我們輸入信息。一個用來接收服務器發來的信息。這兩個文本框分別寫上實例名稱爲txtRecevie和txtInput。然後我們在事件發送數據和接收數據的地方做一點修改
onBtnSendClick函數修改如下:
private function onBtnSendClick(e:MouseEvent):void
{
if (isConnect)
{
var str:String = txtInput.text;
socket.writeUTFBytes(str + "\n");
socket.flush();
}
else
{
trace("服務器沒接連或已斷開!")
}
}

onSocketData函數修改如下:
private function onSocketData(e:Event):void
{
var str:String = socket.readMultiByte(socket.bytesAvailable,"UTF-8");
tctRecevie.text = str;
}
 
 
 
服務端我們也作相應的修改,把接收到的數據轉發給客戶端
將 out.println("cba");
改爲 out.println(str);
然後大家可以測試一下。如果有收到你發出的字符串,說明代碼寫對了。
這裏呢,我希望大家保存一下這個版本。因爲接下來的改動會比較大,當然也會更像一個聊天程序。
 
 
 
接下來,
客戶端Socket的數據發送不再用socket.writeUTFBytes();而改用socket.writeUTF();
而服務器也對應的將BufferedReader的readLine()方法改爲用DataInputStream的readUTF()方法。

客戶端完整代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var socket:Socket;
private var isConnect:Boolean = false;
public function Main()
{
socket = new Socket();//新建一個Socket socket.addEventListener(Event.CONNECT, onSocketConnect);
//偵聽Socket是否已連接上。;
socket.addEventListener(Event.CLOSE, onSocketSeverClose);
//偵聽服務器是否已關閉。;
socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData );
//偵聽服務端是否有消息發送過來。; btnConn.addEventListener(MouseEvent.CLICK, onBtnConnClick);
btnSend.addEventListener(MouseEvent.CLICK, onBtnSendClick);
} private function onBtnConnClick(e:MouseEvent):void
{
socket.connect( "localhost", 5678);//連接到服務器;
}

private function onBtnSendClick(e:MouseEvent):void
{
if (isConnect)
{
var str:String = txtInput.text;
//socket.writeUTFBytes(str + "\n");
socket.writeUTF(str);
socket.flush();
}
else
{
trace("服務器沒接連或已斷開!")
}
} private function onSocketConnect(e:Event):void
{
trace("已連接上服務器!");
isConnect = true;
} private function onSocketData(e:Event):void
{
var str:String = socket.readMultiByte(socket.bytesAvailable,"UTF-8");
tctRecevie.text = str;
} private function onSocketSeverClose(e:Event):void
{
trace("服務器已關閉!");
isConnect = false;
}
}
}

服務端完整代碼如下:
import java.io.*;
import java.net.*;
public class Server {

public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678);//建立一個Socket服務端。
while(true)
{

Socket client=server.accept();//等待客戶端連接,如果沒有客戶端連接,程序會停在此行,而不會執行下一行。
System.out.println("客戶端已連接!");//當有客戶端連接上來的時候,打印輸出客戶端已連接。
//BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
//String str=in.readLine();
DataInputStream dis = new DataInputStream(client.getInputStream());
String str=dis.readUTF();
System.out.println(str);
PrintWriter out=new PrintWriter(client.getOutputStream());
out.println(str);
out.flush();
}
}
}

這裏大家發現有幾個問題,客戶端發送數據後,輸入框沒有清空,而且數據只能發一次。下面我們處理一下這些問題。並且把客戶端接受和服務端的發送也改一下。
客戶端代碼如下:
package
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.Socket;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var socket:Socket;
private var isConnect:Boolean = false;
public function Main()
{
socket = new Socket();//新建一個Socket socket.addEventListener(Event.CONNECT, onSocketConnect);
//偵聽Socket是否已連接上。;
socket.addEventListener(Event.CLOSE, onSocketSeverClose);
//偵聽服務器是否已關閉。;
socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData );
//偵聽服務端是否有消息發送過來。; btnConn.addEventListener(MouseEvent.CLICK, onBtnConnClick);
btnSend.addEventListener(MouseEvent.CLICK, onBtnSendClick);
} private function onBtnConnClick(e:MouseEvent):void
{
socket.connect( "localhost", 5678);//連接到服務器;
}

private function onBtnSendClick(e:MouseEvent):void
{
if (isConnect)
{
var str:String = txtInput.text;
socket.writeUTF(str);
socket.flush();
txtInput.text = "";
}
else
{
trace("服務器沒接連或已斷開!")
}
} private function onSocketConnect(e:Event):void
{
trace("已連接上服務器!");
isConnect = true;
} private function onSocketData(e:Event):void
{
//var str:String = socket.readMultiByte(socket.bytesAvailable,"UTF-8");
var str:String = socket.readUTF();
tctRecevie.text = tctRecevie.text + str + "\n";
} private function onSocketSeverClose(e:Event):void
{
trace("服務器已關閉!");
isConnect = false;
}
}
}

服務端代碼如下:
import java.io.*;
import java.net.*;
public class Server { public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678);//建立一個Socket服務端。
DataInputStream dis = null;
DataOutputStream dos = null;

while(true)
{ Socket client=server.accept();//等待客戶端連接,如果沒有客戶端連接,程序會停在此行,而不會執行下一行。
System.out.println("客戶端已連接!");//當有客戶端連接上來的時候,打印輸出客戶端已連接。
while(true)
{
dis = new DataInputStream(client.getInputStream());
String str=dis.readUTF();
System.out.println(str);
dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(str);
}
}
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章