最近做一个手机APP项目,要用到TCP Socket。因为我不会Android或IOS的原生开发,所以选择了uni-app这个里用HTML5技术做APP的技术框架,但uni-app并未封装对原生TCP Socket的支持(支持HTTP,WebSocket就足够大多数APP使用了),所以,需要用到Native.js(框架支持Native.js,一般使用HTML5技术做APP的框架都支持)调用android原生接口,也可以调用android自带的java库。
本文仅介绍Java的Socket编程。我们正式开始。
服务器端先建立监听套接字服务,然后在无限循环里等待连接过来,来一个连接以后,创建一个线程来为这个套接字服务,方式也很直接,接收信息后原样返回。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
public class SocketServer {
public static void main(String[] args) throws IOException{
//创建Socket
@SuppressWarnings("resource")
ServerSocket listenSocket = new ServerSocket(10000);
System.out.println("服务器正在监听...");
//等待连接的Socket,他在等生成实例,生成了便说明有连接成功了
Socket socket ;
while(true) {
socket = listenSocket.accept();
System.out.println("有新连接到来,端口号为" + socket.getPort());
//每接收到一个客户端连接刚创建一个线程来处理该连接的情况
Thread thread = new Thread(new MyRunnable(socket));
thread.start();
}
}
}
//创建一个内部类来为每个连接处理线程情况
class MyRunnable implements Runnable{
Socket socket;
public MyRunnable(){ }
public MyRunnable(Socket socket){
this.socket = socket;
}
@Override
public void run() {
if(socket == null ){
return ;
}
InputStream inStream = null;
BufferedReader bufferReader = null;
OutputStream outStream = null;
PrintWriter pintWriter = null;
try {
inStream = socket.getInputStream();
outStream = socket.getOutputStream();
bufferReader = new BufferedReader(new InputStreamReader(inStream));
pintWriter = new PrintWriter(outStream);
String text = new String();
while (true) {
text = bufferReader.readLine();
if (text == null) {
System.out.println("客户端已断开");
break;
}
if (text.isEmpty() || text == "exit") {
break;
}
System.out.println("收到:" + text);
// 将消息原样返回给客户端
System.out.println("发送:" + text);
pintWriter.write(text + "\n");
pintWriter.flush();
}
//关闭接收数据
socket.shutdownInput();
//关闭输出流
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭所在资源(与创建反序)
try {
pintWriter.close();
outStream.close();
bufferReader.close();
inStream.close();
if(null != socket) {
socket.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
客户端则建立连接后无限循环发送信息,然后接收服务器反馈回来的信息(这是大多数业务的场景),直到输入exit断开连接。
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketClient {
public static void main(String[] args) throws UnknownHostException, IOException {
connectServer();
}
/**
* 建立Socket 连接方法
* @param num
* @param msg
*/
public static void connectServer() {
BufferedReader bufferReader = null;
InputStream inStream = null;
PrintWriter printWriter = null;
OutputStream outStream = null;
Socket socket = null ;
Scanner input = new Scanner(System.in);
try{
String address = "localhost";
int port = 10000;
System.out.println("连接服务器...");
socket = new Socket(address, port);
inStream = socket.getInputStream();
outStream = socket.getOutputStream();
bufferReader = new BufferedReader(new InputStreamReader(inStream));
printWriter = new PrintWriter(outStream);
String text;
while (true) {
System.out.println("请输入要发送的内容并回车:");
text = input.nextLine();
if (text == "exit") {
break;
}
System.out.println("发送:" + text);
printWriter.write(text + "\n");
printWriter.flush();
System.out.println("已发送");
text = bufferReader.readLine();
if (text == null) {
System.out.println("服务器断开");
break;
}
System.out.println("收到:" + text);
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
bufferReader.close();
printWriter.close();
inStream.close();
if(null != socket) {
socket.shutdownOutput();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
附上Java的API手册地址:https://docs.oracle.com/javase/8/docs/api/
这里要说明的是:实际项目中,服务器端要考虑客户端的超时退出,以防止客户端连上来以后断网了,然后客户端关机了的情况导致服务器维护多个无效连接。
客户端也同理要考虑自己断网后用户还在操作的情况。
所以建议用 setSoTimeout 方法设置SO_TIMEOUT的时间,使读接口不会一直阻塞。
在用Linux C编程里,也要考虑这些事情的。这个跟TCP协议有关系。
附:本文代码源自网址:网络编程:Java Socket通信实现(一)这篇文章,感谢作者的代码示例。