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));
}
}
然后运行程序可以看出效果