Java的Socket客户端多线程实例
最近看博客,发现了一个比较好用的Java原生Socket通信程序,但是它传输接收的都是原始字符串,我们知道实际用的时候,很少用原生的字符串传,都是编码成字节,做一些自定义协议转换后才传,目的是加密和防止粘包丢包脏包,而且传输的是字节数组,很少直接传串的。而且原博客里的代码有个bug,就是发送完消息,没等接收,输出流就给关闭了,造成接收线程无法收到服务端发来的消息,一直报Socket is Closed,所以我稍微改了一下,在这里分享一下,我只改了客户端,服务端同理,不在赘述。
1. 所需包引用导入
这是所需导入的类库包,建议从Maven上链接自动导入。
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import java.io.*;
import java.math.BigInteger;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
2. 源代码讲解
看起来不复杂,定义一个Client类,继承Thread线程类,这点跟Python的多线程差不多,不知道到底谁抄的谁的,然后定义全局的Socket对象,和全局的 输出流对象,这点儿是我后改。然后重写run的执行方法,在run 方法中先异步另起一个线程调用一个发送消息的方法,然后继续走主流程,在主线程里等待收到的服务器消息。
在发送消息的时候,需要先把待发送的打包好的自定义对象转换成json串,然后按自定义的规则将字符串转换成byte数组,再发送出去。这里的StrConvetToByteArray(string jsonStr)就是将json串按照自定义的规则转换为byte数组的方法,该方法需要自己去实现。因为自定义的协议头多种多样,可以随意设计。
然后就是在负责接收消息的主线程中的 有个ByteAarryConvertToString(byte[] receiveMsg)方法,该方法的作用是将收到的服务端返回的字节数组转成字符串,方法名是我随意起的,这里需要自己去实现。其实就是和StrConvetToByteArray(string jsonStr)方法反着来就行,类似于一个编码,一个解码。
public class Client extends Thread {
//定义一个Socket对象
Socket socket = null;
//输出流写操作
OutputStream os= null;
public Client(String host, int port) {
try {
//需要服务器的IP地址和端口号,才能获得正确的Socket对象 socket = new Socket(host, port);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
//客户端一连接就可以写数据给服务器了
new sendMessThread().start();
super.run();
try {
System.out.println(socket.isConnected());
// 读Sock里面的数据
InputStream s = socket.getInputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = s.read(buf)) != -1) {
// 通过自定义的协议将读取的字节流转换成字符串。
String msgServer = ByteAarryConvertToString(buf);
System.out.println("Server Message:" + msgServer);
}
s.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//往Socket里面写数据,需要新开一个线程
class sendMessThread extends Thread{
@Override
public void run() {
super.run();
// 自定义对象
CObject cc = new CObject ("admin","123456",
"test",df.format(new Date()),
UUID.randomUUID().toString(),"");
// 用Gson将对象序列化成转成Json串
Gson gson = new GsonBuilder().create();
String cJsonStr= gson.toJson(cc);
System.out.println(cJsonStr);
try {
byte[] serverData= StrConvetToByteArray(cJsonStr);
os= socket.getOutputStream();
os.write(serverData);
os.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (DecoderException e) {
e.printStackTrace();
}
}
}
//函数入口
public static void main(String[] args) {
//需要服务器的正确的IP地址和端口号
Client clientTest=new Client("192.168.1.4", 54001);
clientTest.start();
}
}
3. 代码出处链接
- 《Java的Socket通信简单实例》
https://www.cnblogs.com/luxd/p/10249898.html