Socket也称为“套接字”,是网络通信中的概念,它分为流式套接字和用户数据报套接字两种,分别对应于网络的传输控制层的TCP和UDP协议。TCP协议是面向连接的协议,提供稳定的双向通信功能,TCP连接的建立需要经过“三次握手”才能生成,为了提供稳定的数据传输功能,其本身提供了超时重传机制,因此具有很高的稳定性;而UDP是无连接的,提供不稳定的单向通信功能,当然UDP也可以实现双向通信功能。在性能上,UDP具有更好的效率,其缺点是不保证数据一定能够正确传输,尤其是在网络拥塞的情况下。
使用Socket来通信,有两点需要注意,首先需要声明权限:
其次要注意不能在主线程中访问网络,因为这会导致我们的程序无法在Android4.0及其以上的设备中运行,会抛出如下异常:android.os.NetworkOnMainThreadException。而且进行网络操作很可能是耗时的,如果放在主线程中会影响程序的响应效率,从这方面来说,也不应该在主线程中访问网络。实际上通过Socket不仅仅能实现进程间通信,还可以实现设备间的通信,当然前提是这些设备之间的IP地址互相可见。
/*** 客户端*/
public class TCPClientActivityextends Activityimplements View.OnClickListener {
private static final int MESSAGE_RECEIVE_NEW_MSG =1;
private static final int MESSAGE_SOCKET_CONNECTED =2;
private ButtonmSendButton;
private TextViewmMessageTextView;
private EditTextmMessageEditText;
private PrintWritermPrintWriter;
private SocketmClientSocket;
private HandlermHandler =new Handler() {
@Override
public void handleMessage(Message msg) {
// super.handleMessage(msg);
switch (msg.what) {
case MESSAGE_RECEIVE_NEW_MSG: {
mMessageTextView.setText(mMessageTextView.getText() + (String) msg.obj);
break;
}
case MESSAGE_SOCKET_CONNECTED: {
mSendButton.setEnabled(true);
break;
}
default:
break;
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activtiy_tcpclient);
mMessageTextView = findViewById(R.id.msg_container);
mSendButton = findViewById(R.id.send);
mSendButton.setOnClickListener(this);
mMessageEditText = findViewById(R.id.msg);
Intent service =new Intent(this, TCPServerService.class);
startService(service);
new Thread() {
@Override
public void run() {
connectTCPServer();
}
}.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mClientSocket !=null) {
try {
mClientSocket.shutdownInput();
mClientSocket.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onClick(View v) {
if (v ==mSendButton) {
final String msg =mMessageEditText.getText().toString();
if (!TextUtils.isEmpty(msg) &&mPrintWriter !=null) {
new Thread(new Runnable() {
@Override
public void run() {
mPrintWriter.println(msg);
}
}).start();
mMessageEditText.setText("");
String time = formatDateTime(System.currentTimeMillis());
final String showedMsg ="self" + time +":" + msg +"\n";
mMessageTextView.setText(mMessageTextView.getText() + showedMsg);
}
}
}
private StringformatDateTime(long time) {
return new SimpleDateFormat("(HH:MM:ss)").format(new Date(time));
}
private void connectTCPServer() {
Socket socket =null;
while (socket ==null) {
try {
socket =new Socket("localhost", 8688);
mClientSocket = socket;
mPrintWriter =new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
System.out.println("connect server success");
}catch (IOException e) {
SystemClock.sleep(1000);
System.out.println("connect tcp server failed,retry... ");
}
}
try {
//接收服务器端的消息
BufferedReader br =new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!TCPClientActivity.this.isFinishing()) {
String msg = br.readLine();
System.out.println("receive:" + msg);
if (msg !=null) {
String time = formatDateTime(System.currentTimeMillis());
final String showedMsg ="server " + time +":" + msg +"\n";
mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, showedMsg).sendToTarget();
}
}
System.out.println("quit...");
mPrintWriter.close();
br.close();
socket.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
/** * 服务端代码 */
public class TCPServerServiceextends Service {
private boolean mIsServiceDestoryed =false;
private String[]mDefinedMessages =new String[]{
"你好啊,哈哈",
"请问你叫什么名字",
"今天深圳天气很好呀,shy",
"你知道吗?我可是可以和多个人聊天的哦",
"给你讲个笑话吧:据说爱笑的人运气不会太差,不知道真假。"
};
@Override
public void onCreate() {
new Thread(new TcpServer()).start();
super.onCreate();
}
@Nullable
@Override
public IBinderonBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
mIsServiceDestoryed =true;
super.onDestroy();
}
private class TcpServerimplements Runnable {
@Override
public void run() {
ServerSocket serverSocket =null;
try {
serverSocket =new ServerSocket(8688);
}catch (IOException e) {
System.err.println("establish tcp server failed,port:8688");
e.printStackTrace();
return;
}
while (!mIsServiceDestoryed) {
//接受客户顿请求
try {
final Socket client = serverSocket.accept();
System.out.println("accept");
new Thread() {
@Override
public void run() {
try {
responseClient(client);
}catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void responseClient(Socket client)throws IOException {
//用于接受客户端消息
BufferedReader in =new BufferedReader(new InputStreamReader(client.getInputStream()));
//用于向客户端发送消息
PrintWriter out =new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
out.println("欢迎来到聊天室!");
while (!mIsServiceDestoryed) {
String str = in.readLine();
System.out.println("msg from client:" + str);
if (str ==null) {
//客户端断开连接
break;
}
int i =new Random().nextInt(mDefinedMessages.length);
String msg =mDefinedMessages[i];
out.println(msg);
System.out.println("send:" + msg);
}
System.out.println("client quit.");
//关闭流
in.close();
out.close();
client.close();
}
}