1.概述
一个简单的Socket通信示例,用于实现Java服务端与Android客户端间的通讯。
整体逻辑
Server端:新开一个线程,启动Server服务端,使用while监听当前端口是否已经进入阻塞状态,如果进入,则表示有连接请求,进行处理(接收/发送消息,这里我设置的是一次通讯–通讯完毕后关闭服务端);
Client端:打开App,输入要发送的内容,点击发送按钮开始新建线程建立Socket请求进行数据的发送、读取。数据读写方式
java.io.DataOuputStream.writeUTF(String str)// 方法将一个字符串写入使用经修订的UTF-8编码的基础输出流
可能产生异常:
IOException – 如果发生I/O错误。java.io.DataInputStream.readUTF()// 方法读取在已使用UTF-8修改版格式编码的字符串。字符的字符串从UTF解码,并返回为字符串
可能产生异常:
IOException – 如果流已关闭或发生或任何I/ O错误。
EOFException – 如果输入流已经到达末端。
UTFDataFormatException – 如果字节不表示一个有效的经修订的UTF-8编码。
2.服务端代码
package com.zihao.socketserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @ClassName:SocketServer
* @Description:TODO<Socket服务端代码>
* @author:zihao
* @date:2015年12月21日 下午3:42:12
* @version:v1.0
*/
public class SocketServer implements Runnable {
private static final String TAG = "【服务器】";
private static final int PORT = 54321;// 端口号
public void run() {
try {
// // 创建ServerSocket
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println(TAG + "已启动.");
// 一旦有堵塞,则表示服务器与客户端获得了连接
while (true) {
// 判断服务端是否已是关闭状态
if (serverSocket.isClosed()) {// 服务端已关闭
return;
}
// 接受客户端请求
Socket client = serverSocket.accept();
System.out.println(TAG + "接受客户端连接请求.");
// 用于接收客户端消息
DataInputStream dis = new DataInputStream(
client.getInputStream());
// 用于向客户端发送消息
DataOutputStream dos = new DataOutputStream(
client.getOutputStream());
try {
String str = dis.readUTF();
System.out.println(TAG + "收到内容:" + str);
String outStr = "服务器反馈的消息";
System.out.println(TAG + "发送内容:" + outStr);
dos.writeUTF(outStr);
dos.flush();
// 关闭流
dis.close();
dos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭
client.close();
System.out.println(TAG + "关闭与客户端连接");
serverSocket.close();
System.out.println(TAG + "关闭");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// main函数,开启服务器
public static void main(String a[]) {
Thread desktopServerThread = new Thread(new SocketServer());
desktopServerThread.start();
}
}
3.Android客户端代码
package com.example.socketclient;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import android.util.Log;
/**
* @ClassName:SocketRequest
* @Description:TODO<Socket请求线程类>
* @author:zihao
* @date:2015年12月18日 上午9:22:56
* @version:v1.0
*/
public class SocketRequest extends Thread {
private static final String TAG = SocketRequest.class.getSimpleName();
private String mServerHost;// 服务器地址
private int mServerPort;// 服务端口号
private String mSendMessage;// 要发送的消息
public SocketRequest(String serverHost, int serverPort, String sendMessage) {
// TODO Auto-generated constructor stub
this.mServerHost = serverHost;
this.mServerPort = serverPort;
this.mSendMessage = sendMessage;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Socket socket = new Socket();
try {
Log.d(TAG, "请求连接到服务器...");
SocketAddress socketAddress = new InetSocketAddress(mServerHost,
mServerPort);
socket.connect(socketAddress, 5 * 1000);// 设置目标地址,请求超时限制
// 判断是否连接成功
if (socket.isConnected()) {
// 发送消息
DataOutputStream dos = new DataOutputStream(
socket.getOutputStream());
Log.d(TAG, "连接成功,开始发送消息,发送内容:" + mSendMessage);
dos.writeUTF(mSendMessage);// 服务区/客户端双方的写/读方式要一直,否则会报错
dos.flush();// 刷新输出流,使Server马上收到该字符串
// 接收服务器消息
DataInputStream dis = new DataInputStream(
socket.getInputStream());
Log.d(TAG, "接收到服务器反馈消息:" + dis.readUTF());
dos.close();
dis.close();
} else {
Log.e(TAG, "未能成功连接至服务器!");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
if (e instanceof SocketTimeoutException) {
Log.e(TAG, "连接超时!");
} else {
Log.e(TAG, "通讯过程发生异常:" + e.toString());
}
} finally {
try {
socket.close();
this.interrupt();
Log.d(TAG, "关闭连接.");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
调用方法
new SocketRequest("服务器地址", 端口号, "要发送的内容").start();
使用权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />