一、Android客户端
- 创建可缓存线程池:Executors.newCachedThreadPool();该方法返回的是一个ExecutorService接口,而这个接口继承Executor接口,Executor只包含一个execute()。
- execute()方法的参数为一个Runnable,返回值为void。
- Message类:获取Message对象的最好方法是调用Message.obtain()或者Handler.obtainMessage(), 这样是从一个可回收对象池中获取Message对象。
- 添加权限:
- 在MainActivity中初始化界面元素,绑定按钮监听事件,注册广播来发送信息
private void findView() {
btnStartClient = (Button) findViewById(R.id.btn_tcpClientConn);
btnCloseClient = (Button) findViewById(R.id.btn_tcpClientClose);
btnClientSend = (Button) findViewById(R.id.btn_tcpClientSend);
editClientPort = (EditText) findViewById(R.id.edit_tcpClientPort);
editClientIp = (EditText) findViewById(R.id.edit_tcpClientIp);
editClientSend = (EditText) findViewById(R.id.edit_tcpClientSend);
MsgList = (TextView) findViewById(R.id.txt_MsgList);
}
private void bindListener() {
btnStartClient.setOnClickListener(myBtnClicker);
btnCloseClient.setOnClickListener(myBtnClicker);
btnClientSend.setOnClickListener(myBtnClicker);
}
private void bindReceiver() {
IntentFilter intentFilter = new IntentFilter("tcpClientReceiver");
registerReceiver(myBroadcastReceiver, intentFilter);//注册广播
}
private void Init() {
btnCloseClient.setEnabled(false);
btnClientSend.setEnabled(false);
}
- 实现按钮“连接服务器”“关闭连接”“发送信息”的点击事件
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_tcpClientConn:
btnStartClient.setEnabled(false);
btnCloseClient.setEnabled(true);
btnClientSend.setEnabled(true);
String ip=editClientIp.getText().toString();
String port=editClientPort.getText().toString();
tcpClient = new TcpClient(ip, getPort(port));
exec.execute(tcpClient);
break;
case R.id.btn_tcpClientClose:
tcpClient.closeSelf();
btnStartClient.setEnabled(true);
btnCloseClient.setEnabled(false);
btnClientSend.setEnabled(false);
break;
case R.id.btn_tcpClientSend:
SendMsg = editClientSend.getText().toString();
Message message = Message.obtain();
message.what = 2;
message.obj = SendMsg;
myHandler.sendMessage(message);//显示在消息列表中
exec.execute(new Runnable() {
@Override
public void run() {
tcpClient.send(SendMsg);//发送消息
}
});
editClientSend.setText("");
break;
}
}
private class MyHandler extends android.os.Handler {
private WeakReference mActivity;
MyHandler(MainActivity activity) {
mActivity = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
if (mActivity != null) {
switch (msg.what) {
case 1://读取到的消息
MsgList.append("服务器:" + msg.obj.toString() + "\n");
break;
case 2://我发送的消息
MsgList.append("我:" + msg.obj.toString() + "\n");
break;
}
}
}
}
- 新建TcpClient类,实现Runnable接口,创建客户端Socket对象,来接收、发送消息
- PrintWriter输出流,实现发送消息
- DataInputStream,实现接收消息
public void send(String msg) {
pw.println(msg);
pw.flush();
}
@Override
public void run() {
try {
socket = new Socket(serverIP, serverPort);
socket.setSoTimeout(5000);
pw = new PrintWriter(socket.getOutputStream(), true);
mInputStreams = socket.getInputStream();
mDataInputStream = new DataInputStream(mInputStreams);
} catch (IOException e) {
e.printStackTrace();
}
while (isRun) {
try {
rcvLen = mDataInputStream.read(buff);//接收消息
rcvMsg = new String(buff, 0, rcvLen, "utf-8");
Intent intent = new Intent();
intent.setAction("tcpClientReceiver");
intent.putExtra("tcpClientReceiver", rcvMsg);
MainActivity.context.sendBroadcast(intent);//将消息发送给主界面
if (rcvMsg.equals("QuitClient")) {
isRun = false;
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
pw.close();
mInputStreams.close();
mDataInputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String mAction = intent.getAction();
switch (mAction) {
case "tcpClientReceiver":
String msg = intent.getStringExtra("tcpClientReceiver");//msg:读取到的消息
Message message = Message.obtain();
message.what = 1;//用户自定义的消息代码,这样接受者可以了解这个消息的信息
message.obj = msg;//obj:发送给接收器的任意对象
myHandler.sendMessage(message);
break;
}
}
}
二、Unity服务器端
使用TcpListener实现Unity服务器端,具体流程参照http://blog.sina.com.cn/s/blog_1322690230102y3l4.html,接下来补充一些功能
void StartServer()
{
/// 1.建立TCP监听器TcpListener对象。
listener = new TcpListener(IPAddress.Parse(NetworkValue.ip), NetworkValue.port);
Debug.Log("服务器已开启: ip-" + NetworkValue.ip + " port-" + NetworkValue.port);
listener.Start(); ///2.启动监听器
//侦测连接的客户端
while (true)
{
///3.等待客户端连接过来
TcpClient tcpclient = listener.AcceptTcpClient();//已连接的客户端,阻塞方法
Debug.Log("一个新用户! Client : " + tcpclient.Client.RemoteEndPoint);
if (_clients.Count < maxConnected)
{
//建立玩家连接类(开启每一个玩家的单独线程)
client = new ClientSocket(tcpclient);
_clients.Add(client);
}
else
{
//向该用户发送"已满"
Thread.Sleep(500); //暂停线程500ms
tcpclient.Close();
}
}
}
SendBtn.onClick.AddListener(delegate
{
sendMsg = inputText.text;
inputText.text = "";
textTest.text += "我:" + sendMsg + "\n";
client.sendQueue.Enqueue(sendMsg);
});
三、通讯效果:
四、Android与Unity工程源码:
https://download.csdn.net/download/weixin_39766005/10649955