这是一个socket长连接的程序,代码如下。我是在windows命令窗口运行socket服务器的。如果有机器设备通过我规定好的代码请求服务器,我就给设备建立长连接进行通讯。然后如果有另外的客户端通过规定好的代码请求,我就发送指令给指定设备,然后设备返回信息,再返回给客户端,这种是短连接。但是很奇怪的就是,总有应该是网络的爬虫请求我的程序,总收到一些乱七八糟的字符串,但是因为这些字符串和我规定的不一样,所以是拦截在外面的,建立不了长连接。最麻烦的来了,当程序运行久了以后或者一定时间,我客户端请求服务器短连接就超时了,服务器命令窗口没显示信息,但是如果我ctrl+c结束一下,请求的字符串又能打印出来了了,好像整个程序挂起来没反应,以至于程序很不稳定,设备用久了总是要重启服务器程序才能恢复。新手socket,不知道是否有精通的大神,能解答一下。会不会是接收数据那段出现了问题呢,代码如下:
class SocketThread implements Runnable {
private Socket socket;
public SocketThread(Socket socket) {
this.socket = socket;
}
public void run() {
InputStreamReader isr = null;
BufferedReader br = null;
OutputStreamWriter osr = null;
BufferedWriter bw = null;
try {
isr = new InputStreamReader(socket.getInputStream());
br = new BufferedReader(isr);
osr = new OutputStreamWriter(socket.getOutputStream());
bw = new BufferedWriter(osr);
char[] chars = new char[1024];
int len;
String resultMsg = "";
while((len = br.read(chars)) != -1){
if (1024 == len) {
resultMsg += chars;
}
else {
for (int i = 0; i < len; i++) {
resultMsg += chars[i];
}
resultMsg = resultMsg.trim();
System.out.println("data:"+resultMsg);
/**
* 新设备连接
*/
if(resultMsg.indexOf("LSKJ:")!=-1){
// 下面这个方法是保存socket到map中
ConnectNew(resultMsg, socket, bw);
}
/**
* 发送代码
*/
if(resultMsg.indexOf("<CODE>")!=-1){
// 普通客户端连接
int tradeCode = Integer.parseInt(SocketUtil.getXMLData(resultMsg, "CODE"));
switch (tradeCode) {
case 100:// 100代码:往设备电路板发送指令
String command = SocketUtil.getXMLData(resultMsg, "COMMAND");
String deviceIp = SocketUtil.getXMLData(resultMsg, "IP");// IP地址
int devicePort = Integer.parseInt(SocketUtil.getXMLData(resultMsg, "PORT")); // 端口
Socket sourceSocket = socketMap.get(devicePort);
clientMap.put(socket.getPort(), socket);
Writer targetWriter = new OutputStreamWriter(sourceSocket.getOutputStream());
targetWriter.write(command+":LSYD:"+socket.getPort());
targetWriter.flush();
break;
case 101:// 101代码:查询socket的数据
StringBuffer returnMsg = new StringBuffer();
if(!socketMap.isEmpty()){
for (Socket socket:socketMap.values()) {
returnMsg.append(socket.getInetAddress().getHostAddress()).append(":").append(socket.getPort());
returnMsg.append("\n");
}
}else{
returnMsg.append(" socketMap is null");
}
bw.write(returnMsg.toString());
bw.flush();
break;
default:
break;
}
}
/**
* 响应代码
*/
if(resultMsg.indexOf("LSYD:")!=-1){
/**
* 返回例子:
* OUDC1_??:LSYD:10001 OFF
*/
String[] msg = resultMsg.split(":");
if(msg.length>=2){
String returnCommand = resultMsg.split(":")[2];
if(returnCommand.length()>=4){
// 取出返回端口号
returnCommand = returnCommand.substring(0, 5);
String regEx="[^0-9]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(returnCommand);
// 端口号
int clientPort = Integer.parseInt(m.replaceAll("").trim());
//System.out.println("端口号是:"+clientPort);
// 返回结果
String result = resultMsg.substring(resultMsg.lastIndexOf(" ")+1,resultMsg.length());
//取出socket返回
Socket clientSocket = clientMap.get(clientPort);
if(clientSocket!=null){
Writer targetWriter = new OutputStreamWriter(clientSocket.getOutputStream());
targetWriter.write(result);
targetWriter.flush();
clientMap.remove(clientPort);
}
}
}
}
}
resultMsg ="";
}
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
}
代码解释一下,当有LSKJ:00001请求的话,服务器就建立长连接,同时保存了IP和端口了,然后如果有<CODE>100</CODE><COMMAND>OUDC1_??</COMMAND><IP>192.168.1.222</IP><PORT>55775</PORT>这种信息请求的话,我就知道是要发送给指定的设备,然后等待设备返回指令OUDC1_ON=030:LSYD:54498:OK,我就知道要返回给54498端口的客户端短连接数据了。
TCP Socket连接是双向的,通过四次挥手的方式断开,双方分别调用Socket.close()方法断开连接。连接断开的过程中,一般一方A先断开连接,另一方B发现A断开连接后,也断开连接。为方便表述,将先断开连接的一方A称为“主动断开连接”;后断开的一方B,则为“被动断开连接”。
在一方B阻塞执行in.readUTF()方法时,如果对方A主动断开Socket连接,这个方法会抛出异常。从而在B处理异常时,可以被动的断开这边的连接。
为保证主动断开连接的一方不会阻塞在in.readUTF()方法中,需要先执行socket.shutdownInput()。所以主动断开连接的代码如下。
socket.shutdownInput();
in.close();
socket.close();
被动断开连接的一方,在捕获到in.readUTF()的异常后,断开Socket连接。
复制代码
try {
String s = in.readUTF();
} catch (IOException e) {
// 连接被断开(被动)
try {
in.close();
socket.close();
in = null;
socket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
结合IP域名过滤好一些,像微信公众号哪样的安全认证。
我想知道,你读取的时候是怎么读的,你的代码里是socket不是socketServer端,是否有使用readLine这种等待换行符阻塞的代码,
或者因为需要等待某个结束符出现才解除阻塞的代码段(这个是解决你关掉服务器后反而会显示出之前发过来没显示的数据)。如果没有的话,
看下你的tcp有没有设置超时时间,这个一般是CPU内核的参数,TCP链接要监听下他的idle空间时间内链接的情况,如果空闲时间太长,也会断开
(你文章说这个是短连接,但是并没有具体提到客户端或者服务端主动断开连接,所以是否可以认为你依然TCP是连着的,依然是长连接),如果还是长连接,那么按照四次挥手,客户端断开了,其实服务器是不知道的,所以需要设置TCP的SO__KEEPALIVE,可以让tcp在2小时候发送一个探测报文,自己来判断是否断开连接