Android 客戶端Socket 與 Java服務端ServerSocket
Socket程式設計
一、Java網路程式設計基礎知識
1、兩臺計算機間進行通訊需要以下三個條件:
1)、 IP地址(例如 : 192.168.1.1)
2)、 協議(服務端與客戶端之間雙方自行協商定義協議,簡稱自定義協議)
3)、 埠號(例如 : 8888)
2、TCP/IP協議:
是目前世界上應用最為廣泛的協議,是以TCP和IP為基礎的不同層次上多個協議的集合,也成TCP/IP協議族、或TCP/IP協議棧
TCP:Transmission Control Protocol 傳輸控制協議
IP:Internet Protocol 網際網路協議
3、TCP/IP五層模型
應用層:HTTP、FTP、SMTP、Telnet等
傳輸層:TCP/IP
網路層:
資料鏈路層:
物理層:網線、雙絞線、網絡卡等
4、IP地址
為實現網路中不同計算機之間的通訊,每臺計算機都必須有一個唯一的標識---IP地址。
32位二進位制
5、埠
區分一臺主機的多個不同應用程式,埠號範圍為0-65535,其中0-1023位為系統保留。
如:HTTP:80 FTP:21 Telnet:23
IP地址+埠號組成了所謂的Socket,Socket是網路上執行的程式之間雙向通訊鏈路的終結點,是TCP和UDP的基礎
6、Socket套接字:
網路上具有唯一標識的IP地址和埠組合在一起才能構成唯一能識別的識別符號套接字。
Socket原理機制:
通訊的兩端都有Socket
網路通訊其實就是Socket間的通訊
資料在兩個Socket間通過IO傳輸
7、Java中的網路支援
針對網路通訊的不同層次,Java提供了不同的API,其提供的網路功能有四大類:
InetAddress:用於標識網路上的硬體資源,主要是IP地址
URL:統一資源定位符,通過URL可以直接讀取或寫入網路上的資料
Sockets:使用TCP協議實現的網路通訊Socket相關的類
Datagram:使用UDP協議,將資料儲存在使用者資料報中,通過網路進行通訊。
二、TCP程式設計
1、TCP協議是面向連線的、可靠的、有序的、以位元組流的方式傳送資料,通過三次握手方式建立連線,形成傳輸資料的通道,在連線中進行大量資料的傳輸,效率會稍低
2、Java中基於TCP協議實現網路通訊的類
客戶端的Socket類
伺服器端的ServerSocket類
3、通訊步驟
① 服務端建立ServerSocket和Socket 客戶端建立Socket
服務端: ServerSocket ss = new ServerSocket(PORT); //
Socket s = ss.accept();
客戶端: Socket clientSocket = new Socket(IP,PORT);
② 開啟連線到Socket的輸入/輸出流
InputStream in = server.getInputStream();
OutputStream out = server.getOutputStream();
③ 按照協議對Socket進行讀/寫操作
④ 關閉輸入輸出流、關閉Socket
in.close();
out.close();
三、服務端
public class ServerSocketDemo { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(9988); Socket socket = serverSocket.accept(); InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String info = null; while ((info = br.readLine()) != null) { System.out.println("我是伺服器,客戶端說:" + info); } socket.shutdownInput();// 關閉輸入流 // 4、獲取輸出流,響應客戶端的請求 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("歡迎您!"); pw.flush(); // 5、關閉資源 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); serverSocket.close(); }
}
四、客戶端
1、建立一個單例Socket管理類·
public class SocketManager {
private static final String TAG = "SocketManager";
public static Socket clientSocket = null;
private int PORT; //埠號
private String IP;
/**
* 埠
*/
public static SocketManager instance = new SocketManager();
private SocketManager() {
clientSocket = connect();
}
public static SocketManager getInstance() {
return instance;
}
public static Socket getClientSocket() {
return clientSocket;
}
public static void setClientSocket(Socket socket){
clientSocket = socket;
}
/**
* 獲取當前socket例項
*/
public Socket connect() {
new Thread(new Runnable() {
@Override
public void run() {
try {
clientSocket = new Socket(IP,PORT);
setClientSocket(clientSocket);
readSocketData(clientSocket);
//sendHeartBeat(clientSocket);
LogUtils.e("TAG","連線成功...");
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
return clientSocket;
}
/**
* 傳送心跳包
* ThreadPoolManager.getSingleInstance().execute() 執行緒管理類
* */
public void sendHeartBeat(Socket socket){
ThreadPoolManager.getSingleInstance().execute(new SendData(socket));
}
/**
* 接收服務端資料
* */
public void readSocketData(Socket socket){
ThreadPoolManager.getSingleInstance().execute(new ReceiveData(socket));
}
/**
* 斷開連線
*/
public void disConnect() throws IOException {
if (clientSocket != null) {
clientSocket.close();
clientSocket = null;
}
}
/**
* 釋放單例, 及其所引用的資源
*/
public void release() throws IOException {
if (instance != null) {
if (clientSocket != null) {
clientSocket.close();
clientSocket = null;
}
instance = null;
}
}
}
2、建立一個SendData執行緒類來負責傳送資料
public class SendData implements Runnable {
private Socket sendsocket;
private PrintWriter printWriter = null;
public SendData(Socket socket) {
this.sendsocket = socket;
}
public void run() {
Socket socket = SocketManager.getClientSocket();
try {
LogUtils.e("TAG", "傳送的資料包:" + JsonUtil.getData());
sendHeartBeatPackage(socket, "要傳送的資料");//資料包
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 傳送資料包到服務端
*/
public int sendHeartBeatPackage(Socket socket1, String msg) {
int returnCode = 0;
if (socket1.isClosed() || socket1 == null) {
returnCode = 0;
}
try {
printWriter = new PrintWriter(socket1.getOutputStream());
printWriter.println(msg);
printWriter.flush();
socket1.getOutputStream().flush();
returnCode = 1;
} catch (Exception e) {
returnCode = 0;
}
return returnCode;
}
}
3、建立一個ReceiveData接收執行緒類
public class ReceiveData implements Runnable {
private Socket socket = null;
private byte[] buffer = new byte[1024];
private int bytes;
InputStream mmInStream = null;
public ReceiveData(Socket mSocket) {
this.socket = mSocket;
}
@Override
public void run() {
try {
mmInStream = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
try {
if ((bytes = mmInStream.read(buffer)) > 0) {
byte[] buf_data = new byte[bytes];
for (int i = 0; i < bytes; i++) {
buf_data[i] = buffer[i];
}
String msg = new String(buf_data);
LogUtils.e("TAG", "來自服務端的資料:" + msg);
}
} catch (IOException e) {
try {
mmInStream.close();
LogUtils.e("TAG", "讀取出現異常...");
} catch (IOException e1) {
e1.printStackTrace();
}
break;
}
}
}
}
五、未完待續。。。
有疑問可直接提問博主,文中可能存在講解不到之處,望大家諒解,也可對博主指出不到之處,之後進行改正。