开头
最近忙于比赛,遇到一个长连接的难题,第一想到就是Socket。比赛中是不会提供第三方框架,经常依赖第三方网络框架的我重新使用Socket发现很多问题,从而总结了这篇文章。方法用意都在注释里。
服务端
- 绑定本地IP端口。
- serverSocket.accept()方法中获取clientSocket
- 获取输出/输入字节流
public class Main {
private static Socket clientSocket = null;
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8888);//绑定本地IP的8888端口
while (true) {
clientSocket = serverSocket.accept();//阻塞获取客户端Socket
while (true) {//不断读取客户端Socket的消息
byte[] b = new byte[1024];
int n = clientSocket.getInputStream().read(b);
String s = new String(b, 0, n);
if (s.equals("close")) {//客户端通知关闭的标识,中止死循环,等待下个客户端Socket
break;
}
System.out.println(s);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//资源释放
try {
if (serverSocket != null) {
serverSocket.close();
}
if (clientSocket != null) {
clientSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
Scanner scanner = new Scanner(System.in);
while (true) {
String s = scanner.next();//从控制台上输入
OutputStream os;
try {
os = clientSocket.getOutputStream();
os.write(s.getBytes());
os.flush();//将输入的文字发给客户端
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
手机客户端
- 监听远程服务端IP端口。
- 获取输出/输入字节流
public class MainActivity extends Activity {
private TextView tvLog;
private Socket socket;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvLog = (TextView) findViewById(R.id.tv_log);
findViewById(R.id.btn_send).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (socket != null) {
try {
OutputStream os = socket.getOutputStream();
os.write("Hello!".getBytes());
os.flush();//将输入的文字发给服务端
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
new Thread(new Runnable() {
@Override
public void run() {
try {
socket = new Socket("10.0.2.2", 8888);//监听服务端IP的8888端口
while (true) {//不断读取服务端的消息
byte[] b = new byte[1024];
int n = socket.getInputStream().read(b);
if (n > 0) {
final String s = new String(b, 0, n);
runOnUiThread(new Runnable() {
@Override
public void run() {
tvLog.setText(s+"\n");
}
});
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
//关闭时通知服务端关闭
try {
socket.getOutputStream().write("close".getBytes());
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意事项
- serverSocket.accept()方法有阻塞作用,直到有客户端进入连接。
- 服务端不断读取客户端数据时,断开最好通知服务端关闭clientSocket。
- 数据传输就getOutputStream和getInputStream方法,客户端只要不关闭就不要关闭流,不然传输不到数据。
- 用哪种方法输入输出流都可以,本人偏向字节流,什么数据都可以传输。
- 服务端要比客户端先启动。
- 上面的例子是为了简单的演示,只了解核心就好了。
不足之处望指教。
1137





