1,Socket通信的实现步骤
Socket 通信和 Binder 通信类似,也是一种 C(Clent)/S(Server) 模型的通信方式。
1.1 Server 服务端
步骤一: 建立一个服务器 Socket
常见的一个服务器 Socket 类是 ServerSocket,ServerSocket 类常用三个方法:binder 、accept、close。
bind 方法为 ServerSocket 绑定 IP 地址和端口号,并开始监听该端口;accept 方法为 ServerSocket 接收请求并返回一个Socket 对象,accept 方法调用之后将一直阻塞,直到有请求达到;close 方法关闭一个 ServerSocket 对象。
初始化是一般需要设定 IP 地址和端口号
步骤二: 通过监听获取一个用于通信的 Socket 对象
执行 accept 方法即可实现
步骤三:
在一个新线程中,通过对 Socket 对象进行封装,分别得到输入、输出流的引用对象,通过这两个对象向 Client 端发送或者从 Client 端接收数据,进而实现 Socket 通信。
一般选择在循环中读取 Client 发送过来的信息,并作出对应的处理,比如反馈 Client 端:自己已成功收到相应的消息。
步骤四:
在适当的时机关闭 Socket 连接。
服务器端代码:
public class SocketTest {
private static final int PORT = 9999;
private List<Socket> mList = new ArrayList<Socket>();
private ServerSocket server = null;
private ExecutorService mExecutorService = null;
private String receiveMsg;
private String sendMsg;
public static void main(String[] args) {
new SocketTest();
}
public SocketTest() {
try {
server = new ServerSocket(PORT); //步骤一
mExecutorService = Executors.newCachedThreadPool();
System.out.println("服务器已启动...");
Socket client = null;
while (true) {
client = server.accept(); //步骤二,每接受到一个新Socket连接请求,就会新建一个Thread去处理与其之间的通信
mList.add(client);
mExecutorService.execute(new Service(client));
}
} catch (Exception e) {
e.printStackTrace();
}
}
class Service implements Runnable {
private Socket socket;
private BufferedReader in = null;
private PrintWriter printWriter=null;
public Service(Socket socket) { //这段代码对应步骤三
this.socket = socket;
try {
printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter( socket.getOutputStream(), "UTF-8")), true);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream(),"UTF-8"));
printWriter.println("成功连接服务器"+"(服务器发送)");
System.out.println("成功连接服务器");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while (true) { //循环接收、读取 Client 端发送过来的信息
if ((receiveMsg = in.readLine())!=null) {
System.out.println("receiveMsg:"+receiveMsg);
if (receiveMsg.equals("0")) {
System.out.println("客户端请求断开连接");
printWriter.println("服务端断开连接"+"(服务器发送)");
mList.remove(socket);
in.close();
socket.close(); //接受 Client 端的断开连接请求,并关闭 Socket 连接
break;
} else {
sendMsg = "我已接收:" + receiveMsg + "(服务器发送)";
printWriter.println(sendMsg); //向 Client 端反馈、发送信息
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
1.2 Client 客户端
步骤一:
初始化 Socket 对象
客户端一般选择在一个新的线程中,初始化一个 Socket 对象,初始化是需要设置 IP 和端口号,以帮助低层网络路由找到相应的服务端进程。
步骤二:
获取与 Server 端通信的引用
此步和 Server 端建立连接后的步骤类似:根据步骤一中获取的 Socket 对象,进行封装,得到相应的输入、输出流对象,这些输入、输出流对象就是和 Server 端进行通信的引用。
步骤三:
通过步骤二中得到的引用,循环的读取(在新线程中) Server 端发送过来的消息,并做相应的处理
步骤四:
在合适的时机关闭与 Server 端的 Socket 连接。
客户端代码:
public class SocketActivity extends AppCompatActivity {
private EditText mEditText;
private TextView mTextView;
private static final String TAG = "TAG";
private static final String HOST = "192.168.23.1";
private static final int PORT = 9999;
private PrintWriter printWriter;
private BufferedReader in;
private ExecutorService mExecutorService = null;
private String receiveMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_socket);
mEditText = (EditText) findViewById(R.id.editText);
mTextView = (TextView) findViewById(R.id.textView);
mExecutorService = Executors.newCachedThreadPool();
}
public void connect(View view) {
mExecutorService.execute(new connectService()); //在一个新的线程中请求 Socket 连接
}
public void send(View view) {
String sendMsg = mEditText.getText().toString();
mExecutorService.execute(new sendService(sendMsg));
}
public void disconnect(View view) {
mExecutorService.execute(new sendService("0"));
}
private class sendService implements Runnable {
private String msg;
sendService(String msg) {
this.msg = msg;
}
@Override
public void run() {
printWriter.println(this.msg);
}
}
private class connectService implements Runnable {
@Override
public void run() {//可以考虑在此处添加一个while循环,结合下面的catch语句,实现Socket对象获取失败后的超时重连,直到成功建立Socket连接
try {
Socket socket = new Socket(HOST, PORT); //步骤一
socket.setSoTimeout(60000);
printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter( //步骤二
socket.getOutputStream(), "UTF-8")), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
receiveMsg();
} catch (Exception e) {
Log.e(TAG, ("connectService:" + e.getMessage())); //如果Socket对象获取失败,即连接建立失败,会走到这段逻辑
}
}
}
private void receiveMsg() {
try {
while (true) { //步骤三
if ((receiveMsg = in.readLine()) != null) {
Log.d(TAG, "receiveMsg:" + receiveMsg);
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(receiveMsg + "\n\n" + mTextView.getText());
}
});
}
}
} catch (IOException e) {
Log.e(TAG, "receiveMsg: ");
e.printStackTrace();
}
}
}
基本的实现步骤就是这样。