您的位置:首页 > 理论基础 > 计算机网络

Android利用Socket(TCP)通信实现即时聊天

2017-01-08 00:53 489 查看
TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。java中的TCP通信都是通过Socket来进行的。

Socket 编程

Socket是应用层与TCP/IP协议簇通讯的中间抽象层,Socket是一组接口,在设计模式中,Socket的设计就是门面模式,它把复杂的TCP/IP协议簇的内容隐藏在套接字接口后面,用户无需关心协议的实现,只需使用Socket提供的接口即可。

套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行进行通信。

java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:

服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。

服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。

服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。

Socket类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。

在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。

连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket。

服务器应用程序通过使用 java.net.ServerSocket 类的构造方法获取一个端口,并且侦听客户端请求。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。

当 Socket 构造方法被调用时,并没有直接去实例化一个 Socket 对象,而它会尝试连接到指定的服务器和端口。

下面是作为服务端接收消息的代码:

package com.example.messagec;

import android.util.Log;

import com.example.messagec.observer.ObserverHolder;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 接收
*/
public class TCPReceiver {

public static final String TAG = "TCPReceiver";

/**
* 接收数据的服务端Socket
*/
private ServerSocket serverSocket;

private ExecutorService executorService = Executors.newSingleThreadExecutor();

/**
* @param serverPort 服务器注册的端口号
*/
public TCPReceiver(int serverPort) {
initSocket(serverPort);
initReceiverMessage();
}

private void initSocket(int serverPort) {
try {
// 创建一个ServerSocket对象,并设置监听端口
serverSocket = new ServerSocket(serverPort);
Log.i(TAG, "isBound=" + serverSocket.isBound() + "  isClosed=" + serverSocket.isClosed());
} catch (IOException e) {
e.printStackTrace();
}
}

private void initReceiverMessage() {
executorService.execute(runnableReceiverMsg);
}

private Runnable runnableReceiverMsg = new Runnable() {
@Override
public void run() {
Socket socket = null;
try {
// 调用ServerSocket的accept()方法,接受客户端所发送的请求,
socket = serverSocket.accept();
// 从Socket当中得到InputStream对象
InputStream inputStream = socket.getInputStream();
byte buffer[] = new byte[10 * 1024];
int temp = 0;
// 从InputStream当中读取客户端所发送的数据
while ((temp = inputStream.read(buffer)) != -1) {
Log.i(TAG, new String(buffer, 0, temp));  //打印接收到的信息

}
} catch (IOException e) {
e.printStackTrace();
}
}
};

}


下面是作为客户端发送消息的代码:

package com.example.messagec;

import android.util.Log;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

/**
* 发送
*/
public class TCPSend {

/**
* 发送数据的客户端Socket
*/
private Socket socket;

private OutputStream out = null;

/**
* @param ip   接收方的ip地址
* @param port 接收方的端口号
*/
public TCPSend(String ip, int port) {
try {
socket = new Socket(ip, port);
out = socket.getOutputStream();
Log.i("---", "isBound" + socket.isBound() + " isConnected" + socket.isConnected());
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* 发送数据
*/
public void sendMessage(String msg) {
Log.i("---", "isBound" + socket.isBound() + " isConnected" + socket.isConnected());

try {
out.write(msg.getBytes());
out.flush();
Log.i("---", msg);
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* 关闭连接
*/
public void close() {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket.isInputShutdown()) { //判断输入流是否为打开状态
try {
socket.shutdownInput();  //关闭输入流
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket.isOutputShutdown()) {  //判断输出流是否为打开状态
try {
socket.shutdownOutput(); //关闭输出流(如果是在给对方发送数据,发送完毕之后需要关闭输出,否则对方的InputStream可能会一直在等待状态)
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket.isConnected()) {  //判断是否为连接状态
try {
socket.close();  //关闭socket
} catch (IOException e) {
e.printStackTrace();
}
}

}

}


下面是Activity代码实现:

package com.example.messagec;

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.messagec.observer.IObservable;
import com.example.messagec.observer.IObserver;
import com.example.messagec.observer.ObserverHolder;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity implements IObserver {

ExecutorService executorService = Executors.newSingleThreadExecutor();

@BindView(R.id.til_message)
TextInputLayout tilMessage;
@BindView(R.id.btn_send_msg)
Button btnSendMsg;
@BindView(R.id.txt_message)
TextView txtMessage;
@BindView(R.id.activity_main)
LinearLayout activityMain;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
startService(new Intent(this, ReceiverMessageService.class));
new Thread(new Runnable() {
@Override
public void run() {
tcpSend = new TCPSend("127.0.0.1",10012);
}
}).start();
ObserverHolder.getInstance().register(this);
}

@Override
protected void onDestroy() {
super.onDestroy();
ObserverHolder.getInstance().unregister(this);
}

@Override
public void onMessageReceived(IObservable observable, final Object msg, int flag) {
switch (flag) {
case ObserverHolder.RECEIVER_MESSAGE:
Log.i("=+++++=",msg+"");
runOnUiThread(new Runnable() {  //切换到主线程更新ui
@Override
public void run() {
txtMessage.setText(msg+"");
}
});

break;
}
}

@OnClick({R.id.btn_send_msg})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_send_msg:
sendMsg();
break;
}
}

/**
* 消息发送的类
*/
private TCPSend tcpSend;

/**
* 发送信息
*/
private void sendMsg() {
executorService.execute(runnable);
}

Runnable runnable = new Runnable() {
@Override
public void run() {
tcpSend.sendMessage(tilMessage.getEditText().getText().toString());
}
};

}


demo下载链接:http://download.csdn.net/detail/chengliang0315/9731750

GIT下载地址: https://code.csdn.net/chengliang0315/tcpmessagedemo.git
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: