Socket
Socket 稱爲"套接字",是網絡通信的概念。分爲流式套接字和數據報套接字。流式套接字將TCP作爲其端對端協議,提供字節流服務。數據包套接字使用UDP協議,提供數據打包發送服務。
TCP協議是面向連接的協議,提供穩定的雙向通信功能。連接的建立需要經過"三次握手"才能完成,具有很高的穩定性。
UDP協議是無連接的,缺點是不保證數據一定能夠正確傳輸。可能會出現丟包事件。
下面我們用TCP來實現一個簡易聊天
創建TCPServerService
package com.example.test.socket;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
/**
* Description:
*/
public class TCPServerService extends Service{
private boolean serverRun = true;
private static final String TAG = "TCPServerService";
private String[] messages = new String[]{
"天王蓋地虎,小雞燉蘑菇。",
"寶塔鎮河妖,蘑菇放辣椒。",
"河妖用大招,二樓彎下腰。",
"莫愁不開懷,二樓出人才。",
"鈦合金狗眼,貞操已用完。",
"糗百無女神,屌絲一大羣。",
"屌絲變色狼,色狼變流氓。",
"宅男尋腐女,腐女已有郎。",
"想富賣切糕,木耳愛香蕉。",
"恨未逢時生,前路很渺茫。",
"尋她千百度,千里聚一趟。",
"玉帝和王母,雪碧兩塊五。",
"只因夢太短,起來洗把臉。"
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
new Thread(new TCPServer()).start();
}
@Override
public void onDestroy() {
serverRun = false;
super.onDestroy();
}
private class TCPServer implements Runnable{
@Override
public void run() {
ServerSocket serverSocket = null;
try {
//監聽8686端口
serverSocket = new ServerSocket(8686);
} catch (IOException e) {
e.printStackTrace();
return;
}
while (serverRun){
try {
final Socket socket = serverSocket.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
responseClient(socket);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void responseClient(Socket socket) throws IOException {
//用於接收客戶端消息
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//用於向客戶端發送消息
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
printWriter.println("歡迎來到大型交友平臺");
while (serverRun){
String msg = bufferedReader.readLine();
Log.e(TAG, "responseClient: receive msg _:" +msg);
if (msg == null) {
break;
}
int i = new Random().nextInt(messages.length);
String replyMsg = messages[i];
printWriter.println(replyMsg);
Log.e(TAG, "responseClient: send msg _:" +replyMsg);
}
bufferedReader.close();
printWriter.close();
socket.close();
}
}
權限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Service註冊
<service android:name=".socket.TCPServerService"
android:process=":TCPServerService"
>
</service>
創建TCPClientActivity
package com.example.test.socket;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.example.test.R;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class TCPClientActivity extends AppCompatActivity {
@BindView(R.id.tv_msg_container)
TextView mTvMsgContainer;
@BindView(R.id.et_msg)
EditText mEtMsg;
@BindView(R.id.btn_send)
Button mBtnSend;
private Intent mIntent;
private Socket mClientSocket;
private static final int MESSAGE_RECEIVE_NEW_MSG = 1;
private static final int MESSAGE_SOCKET_CONNECTED = 2;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_RECEIVE_NEW_MSG: {
mTvMsgContainer.setText(mTvMsgContainer.getText() + (String) msg.obj);
break;
}
case MESSAGE_SOCKET_CONNECTED: {
mBtnSend.setEnabled(true);
break;
}
default:
break;
}
}
};
private PrintWriter mPrintWriter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tcpclient);
ButterKnife.bind(this);
initData();
}
private void initData() {
mIntent = new Intent(this, TCPServerService.class);
startService(mIntent);
new Thread(new Runnable() {
@Override
public void run() {
//連接servc
connectTCPServer();
}
}).start();
}
private void connectTCPServer() {
Socket socket = null;
while (socket == null) {
try {
socket = new Socket("localhost", 8686);
mClientSocket = socket;
mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
//用於接收服務端消息
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!TCPClientActivity.this.isFinishing()){
String serverMsg = bufferedReader.readLine();
if (serverMsg != null) {
String time = formatDateTime(System.currentTimeMillis());
String msg = "servermsg ____ " + time +" : "+serverMsg +"\n";
mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG,msg).sendToTarget();
}
}
bufferedReader.close();
mPrintWriter.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
stopService(mIntent);
if (mClientSocket != null) {
try {
mClientSocket.shutdownInput();
mClientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
super.onDestroy();
}
@OnClick(R.id.btn_send)
public void onViewClicked() {
new Thread(new Runnable() {
@Override
public void run() {
final String msg = mEtMsg.getText().toString();
if (!TextUtils.isEmpty(msg) && mPrintWriter != null) {
mPrintWriter.println(msg);
runOnUiThread(new Runnable() {
@Override
public void run() {
mEtMsg.setText("");
String time = formatDateTime(System.currentTimeMillis());
String showMsg = "clientmsg ____ " + time +" : "+msg +"\n";
mTvMsgContainer.setText(mTvMsgContainer.getText() + showMsg);
}
});
}
}
}).start();
}
@SuppressLint("SimpleDateFormat")
private String formatDateTime(long time) {
return new SimpleDateFormat("(HH:mm:ss)").format(new Date(time));
}
}
然後運行程序可以看出效果