TCP 是傳輸控制協議的縮寫,它保障了兩個應用程序之間的可靠通信。通常用於互聯網協議,被稱 TCP / IP。java中的TCP通信都是通過Socket來進行的。
Socket 編程
Socket是應用層與TCP/IP協議簇通訊的中間抽象層,Socket是一組接口,在設計模式中,Socket的設計就是門面模式,它把複雜的TCP/IP協議簇的內容隱藏在套接字接口後面,用戶無需關心協議的實現,只需使用Socket提供的接口即可。
套接字使用TCP提供了兩臺計算機之間的通信機制。 客戶端程序創建一個套接字,並嘗試連接服務器的套接字。當連接建立時,服務器會創建一個 Socket 對象。客戶端和服務器現在可以通過對 Socket 對象的寫入和讀取來進行進行通信。
java.net.Socket 類代表一個套接字,並且 java.net.ServerSocket 類爲服務器程序提供了一種來監聽客戶端,並與他們建立連接的機制。
以下步驟在兩臺計算機之間使用套接字建立TCP連接時會出現:
– 服務器實例化一個 ServerSocket 對象,表示通過服務器上的端口通信。
– 服務器調用 ServerSocket 類的 accept() 方法,該方法將一直等待,直到客戶端連接到服務器上給定的端口。
– 服務器正在等待時,一個客戶端實例化一個 Socket 對象,指定服務器名稱和端口號來請求連接。
– Socket類的構造函數試圖將客戶端連接到指定的服務器和端口號。如果通信被建立,則在客戶端創建一個 Socket 對象能夠與服務器進行通信。
– 在服務器端,accept() 方法返回服務器上一個新的 socket 引用,該 socket 連接到客戶端的 socket。
連接建立後,通過使用 I/O 流在進行通信,每一個socket都有一個輸出流和一個輸入流,客戶端的輸出流連接到服務器端的輸入流,而客戶端的輸入流連接到服務器端的輸出流。
TCP 是一個雙向的通信協議,因此數據可以通過兩個數據流在同一時間發送.以下是一些類提供的一套完整的有用的方法來實現 socket。
服務器應用程序通過使用 java.net.ServerSocket 類的構造方法獲取一個端口,並且偵聽客戶端請求。 如果 ServerSocket 構造方法沒有拋出異常,就意味着你的應用程序已經成功綁定到指定的端口,並且偵聽客戶端請求。
當 Socket 構造方法被調用時,並沒有直接去實例化一個 Socket 對象,而它會嘗試連接到指定的服務器和端口。
下面是作爲服務端接收消息的代碼:
package com.example.messagec;
import android.util.Log;
import com.example.messagec.observer.ObserverHolder;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 接收
*/
public class TCPReceiver {
public static final String TAG = "TCPReceiver";
/**
* 接收數據的服務端Socket
*/
private ServerSocket serverSocket;
private ExecutorService executorService = Executors.newSingleThreadExecutor();
/**
* @param serverPort 服務器註冊的端口號
*/
public TCPReceiver(int serverPort) {
initSocket(serverPort);
initReceiverMessage();
}
private void initSocket(int serverPort) {
try {
// 創建一個ServerSocket對象,並設置監聽端口
serverSocket = new ServerSocket(serverPort);
Log.i(TAG, "isBound=" + serverSocket.isBound() + " isClosed=" + serverSocket.isClosed());
} catch (IOException e) {
e.printStackTrace();
}
}
private void initReceiverMessage() {
executorService.execute(runnableReceiverMsg);
}
private Runnable runnableReceiverMsg = new Runnable() {
@Override
public void run() {
Socket socket = null;
try {
// 調用ServerSocket的accept()方法,接受客戶端所發送的請求,
socket = serverSocket.accept();
// 從Socket當中得到InputStream對象
InputStream inputStream = socket.getInputStream();
byte buffer[] = new byte[10 * 1024];
int temp = 0;
// 從InputStream當中讀取客戶端所發送的數據
while ((temp = inputStream.read(buffer)) != -1) {
Log.i(TAG, new String(buffer, 0, temp)); //打印接收到的信息
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
}
下面是作爲客戶端發送消息的代碼:
package com.example.messagec;
import android.util.Log;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* 發送
*/
public class TCPSend {
/**
* 發送數據的客戶端Socket
*/
private Socket socket;
private OutputStream out = null;
/**
* @param ip 接收方的ip地址
* @param port 接收方的端口號
*/
public TCPSend(String ip, int port) {
try {
socket = new Socket(ip, port);
out = socket.getOutputStream();
Log.i("---", "isBound" + socket.isBound() + " isConnected" + socket.isConnected());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 發送數據
*/
public void sendMessage(String msg) {
Log.i("---", "isBound" + socket.isBound() + " isConnected" + socket.isConnected());
try {
out.write(msg.getBytes());
out.flush();
Log.i("---", msg);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 關閉連接
*/
public void close() {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket.isInputShutdown()) { //判斷輸入流是否爲打開狀態
try {
socket.shutdownInput(); //關閉輸入流
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket.isOutputShutdown()) { //判斷輸出流是否爲打開狀態
try {
socket.shutdownOutput(); //關閉輸出流(如果是在給對方發送數據,發送完畢之後需要關閉輸出,否則對方的InputStream可能會一直在等待狀態)
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket.isConnected()) { //判斷是否爲連接狀態
try {
socket.close(); //關閉socket
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
下面是Activity代碼實現:
package com.example.messagec;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.messagec.observer.IObservable;
import com.example.messagec.observer.IObserver;
import com.example.messagec.observer.ObserverHolder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity implements IObserver {
ExecutorService executorService = Executors.newSingleThreadExecutor();
@BindView(R.id.til_message)
TextInputLayout tilMessage;
@BindView(R.id.btn_send_msg)
Button btnSendMsg;
@BindView(R.id.txt_message)
TextView txtMessage;
@BindView(R.id.activity_main)
LinearLayout activityMain;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
startService(new Intent(this, ReceiverMessageService.class));
new Thread(new Runnable() {
@Override
public void run() {
tcpSend = new TCPSend("127.0.0.1",10012);
}
}).start();
ObserverHolder.getInstance().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ObserverHolder.getInstance().unregister(this);
}
@Override
public void onMessageReceived(IObservable observable, final Object msg, int flag) {
switch (flag) {
case ObserverHolder.RECEIVER_MESSAGE:
Log.i("=+++++=",msg+"");
runOnUiThread(new Runnable() { //切換到主線程更新ui
@Override
public void run() {
txtMessage.setText(msg+"");
}
});
break;
}
}
@OnClick({R.id.btn_send_msg})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_send_msg:
sendMsg();
break;
}
}
/**
* 消息發送的類
*/
private TCPSend tcpSend;
/**
* 發送信息
*/
private void sendMsg() {
executorService.execute(runnable);
}
Runnable runnable = new Runnable() {
@Override
public void run() {
tcpSend.sendMessage(tilMessage.getEditText().getText().toString());
}
};
}
demo下載鏈接:http://download.csdn.net/detail/chengliang0315/9731750
GIT下載地址: https://code.csdn.net/chengliang0315/tcpmessagedemo.git