之前都是再activity中实现的,当应用销毁的时候客户端也会断开连接,如果没有销毁长时间也会断开连接,因此相关通信需要写在service中。客户端创建一个Connector.java来专门管理相关请求,连接和通信,CoreService作为一个服务在后台处理相关请求ConnectorManager.java来管理Connector里面的请求,CoreService会调用ConnectorManager并发起连接,MainActivity.java发起通信数据
java端代码TCPServer.java
package com.ldw.socket.server;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class TCPServer {
//创建一个容器,存储客户端
//private static List<Socket> clients = new LinkedList<Socket>();
//认证信息和客户端信息
private static Map<String, Socket> clients = new LinkedHashMap<String, Socket>();
public static void main(String[] args) {
int port = 10002;
try {
ServerSocket server = new ServerSocket(port);
while (true) {
// 获得客户端连接
// 阻塞式方法
System.out.println("准备阻塞...");
final Socket client = server.accept();
System.out.println("阻塞完成...");
// 将客户端添加到容器中
//clients.add(client);
//开一个子线程防止阻塞,下面的内容是阻塞式的
new Thread(new Runnable() {
@Override
public void run() {
try {
// 输入流,为了获取客户端发送的数据
InputStream is = client.getInputStream();
// 输出流,给客户端写数据
OutputStream os = client.getOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
System.out.println("准备read...");
while ((len = is.read(buffer)) != -1) {
System.out.println("read完成...");
String text = new String(buffer, 0, len);
System.out.println(text);
if (text.startsWith("#")) {
// 将客户端添加到 容器中
clients.put(text, client);
// 输出数据到客户端
os.write("认证成功".getBytes());
} else {
// 输出数据到客户端
os.write("收到你的请求".getBytes());
//拆分用户名和内容信息
String[] split = text.split(":");
String key = "#" + split[0];
String content = split[1];
System.out.println(content);
// 给谁发消息
Socket s = clients.get(key);
if (s != null) {
System.out.println("is not null");
OutputStream output = s.getOutputStream();
output.write(content.getBytes());
} else {
System.out.println("is null");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端通过Android来实现,布局文件,布局文件有几个按键,来方便触发
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!--
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="认证内容"
android:id="@+id/et_auth"
/>
<Button
android:text="连接"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clickConnect"
/>
<Button
android:text="认证"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clickAuth"
/> -->
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clickMessage"
android:text="通讯" />
<!--
<Button
android:text="断开连接"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clickDisConnect"
/> -->
</LinearLayout>
逻辑代码MainActivity.java界面信息,创建服务,并发送消息
package org.ldw.socket.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.ldw.socket.client.request.AuthRequest;
import org.ldw.socket.client.request.Request;
import org.ldw.socket.client.request.TextRequest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText et;
private EditText et_auth;
private PushReceiver receiver = new PushReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d("activity", "receive");
if (PushReceiver.ACTION_TEXT.equals(action)) {
String text = intent.getStringExtra(PushReceiver.DATA_KEY);
Toast.makeText(getApplicationContext(), text,
Toast.LENGTH_SHORT).show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = (EditText) findViewById(R.id.et);
et_auth = (EditText) findViewById(R.id.et_auth);
startService(new Intent(this, CoreService.class));
IntentFilter filter = new IntentFilter();
filter.addAction(PushReceiver.ACTION_TEXT);
registerReceiver(receiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
public void clickMessage(View v) {
//获取输入框的内容
final String content = et.getText().toString().trim();
if (TextUtils.isEmpty(content)) {
return;
}
ConnectorManager.getInstance().putRequest(content);
}
}
CoreService.java服务,来启动连接,并监听通信,同时发送广播,发送广播的目的是在MainActivity中Toast弹出相关信息,主要是为了在主界面刷新UI
package org.ldw.socket.client;
import org.ldw.socket.client.ConnectorManager.ConnectorListener;
import org.ldw.socket.client.request.AuthRequest;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
public class CoreService extends Service implements ConnectorListener {
private Connector connector;
private ConnectorManager connectorManager;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
connectorManager = ConnectorManager.getInstance();
new Thread(new Runnable() {
@Override
public void run() {
// //创建连接器
// connector = new Connector();
// //监听连接状态
// connector.setConnectorListener(c);
// connector.connect();
// connector.auth("#A");
connectorManager.setConnectorListener(CoreService.this);
connectorManager.connnect(request);
}
}).start();
}
@Override
public void pushData(String data) {
Log.d("coreService", "data : " + data);
Intent intent = new Intent();
intent.setAction(PushReceiver.ACTION_TEXT);
intent.putExtra(PushReceiver.DATA_KEY, data);
sendBroadcast(intent);
}
}
Connector.java客户端三次握手,连接的处理
package org.ldw.socket.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Connector {
private String dstName = "192.168.1.100";
private int dstPort = 10002;
private Socket client;
private ConnectorListener listener;
//先进先出,后进后出
private ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(8);
public Connector() {
}
public void connect() {
try {
// 三次握手
if (client == null || client.isClosed()) {
client = new Socket(dstName, dstPort);
}
new Thread(new RequestWorker()).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream is = client.getInputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = is.read(buffer)) != -1) {
final String text = new String(buffer, 0, len);
System.out.println("text : " + text);
if (listener != null) {
listener.pushData(text);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//进行通信,相当于下面的send
public class RequestWorker implements Runnable {
@Override
public void run() {
// 数据通讯
OutputStream os;
try {
os = client.getOutputStream();
// os.write(content.getBytes());
while (true) {
String content = queue.take();
os.write(content.getBytes());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void auth(String auth) {
putRequest(auth);
/*
// 数据通讯
OutputStream os;
try {
os = client.getOutputStream();
os.write(auth.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
putRequest(auth);
*/
}
public void putRequest(String content) {
try {
queue.put(content);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
public void send(String content) {
// 数据通讯
OutputStream os;
try {
os = client.getOutputStream();
os.write(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
*/
public void disconnect() {
// 断开连接
try {
if (client != null && !client.isClosed()) {
client.close();
client = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
private ConnectorListener listener;
public void setConnectorListener(ConnectorListener listener) {
this.listener = listener;
}
//连接的监听,这个接口是作为回调函数使用的
public interface ConnectorListener {
void pushData(String data);
}
}
ConnectorManager.java连接的管理类,同时监听连接
package org.ldw.socket.client;
import org.ldw.socket.client.Connector.ConnectorListener;
import org.ldw.socket.client.request.AuthRequest;
import org.ldw.socket.client.request.Request;
public class ConnectorManager implements ConnectorListener {
private static ConnectorManager instance;
private Connector connector;
public static ConnectorManager getInstance() {
if (instance == null) {
synchronized (ConnectorManager.class) {
if (instance == null) {
instance = new ConnectorManager();
}
}
}
return instance;
}
private ConnectorManager() {
}
public void connnect(String auth) {
connector = new Connector();
connector.setConnectorListener(this);
connector.connect();
connector.auth(auth);
}
public void connnect(String auth) {
connector = new Connector();
connector.setConnectorListener(this);
connector.connect();
connector.auth(auth);
}
public void putRequest(String request) {
connector.putRequest(request);
}
@Override
public void pushData(String data) {
System.out.println("data : " + data);
if (listener != null) {
listener.pushData(data);
}
}
private ConnectorListener listener;
//连接的监听,这个接口是作为回调函数使用的
public void setConnectorListener(ConnectorListener listener) {
this.listener = listener;
}
public interface ConnectorListener {
void pushData(String data);
}
}
PushReceiver.java广播接收者,接受服务中发送的广播
package org.ldw.socket.client;
import android.content.BroadcastReceiver;
public abstract class PushReceiver extends BroadcastReceiver {
public static final String ACTION_TEXT = "com.ldw.action.text";
public static final String DATA_KEY = "data";
}
Manifist.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.ldw.socket.client"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="org.ldw.socket.client.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="org.ldw.socket.client.CoreService" >
</service>
</application>
</manifest>