概述
既然是长连接就免不了心跳检测,这里使用了一种比较简单的做法:服务端对当前线程计时,重要的话说三遍,服务端、服务端、服务端!如果超时没有收到任何数据就关闭该线程对应的Socket。代码复制粘贴即可运行。
发送时:将String转byte[]
接收时:将byte[]转String
效果图
客户端代码
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class SocketClient
{
public static void main(String[] args)
{
try
{
Socket socket = new Socket("localhost", 8888);
//得到一个输出流,用于向服务器发送数据
OutputStream outputStream = socket.getOutputStream();
System.out.println("请输入16进制数据:");
Scanner sc = new Scanner(System.in);
while (true)
{
String data = sc.nextLine();
if ("exit".equals(data))
{
return;
}
byte[] byteArray = HexStrToByteArray(data);
outputStream.write(byteArray);
//刷新缓冲
outputStream.flush();
//得到一个输入流,用于接收服务器响应的数据
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1]; // 一次读取一个byte
String info = "";
while (true)
{
if (inputStream.available() > 0)
{
inputStream.read(bytes);
String hexStr = ByteArrayToHexStr(bytes);
info += HexStrToStr(hexStr);
//已经读完
if (inputStream.available() == 0)
{
System.out.println("收到来自服务端的信息:" + info);
break;
}
}
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
/**
* 16进制Str转byte[]
*
* @param hexStr
* @return
*/
public static byte[] HexStrToByteArray(String hexStr)
{
if (hexStr == null)
{
return null;
}
if (hexStr.length() == 0)
{
return new byte[0];
}
byte[] byteArray = new byte[hexStr.length() / 2];
for (int i = 0; i < byteArray.length; i++)
{
String subStr = hexStr.substring(2 * i, 2 * i + 2);
byteArray[i] = ((byte) Integer.parseInt(subStr, 16));
}
return byteArray;
}
/**
* byte[]转16进制Str
*
* @param byteArray
*/
public static String ByteArrayToHexStr(byte[] byteArray)
{
if (byteArray == null)
{
return null;
}
char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[byteArray.length * 2];
for (int i = 0; i < byteArray.length; i++)
{
int temp = byteArray[i] & 0xFF;
hexChars[i * 2] = hexArray[temp >>> 4];
hexChars[i * 2 + 1] = hexArray[temp & 0x0F];
}
return new String(hexChars);
}
/**
* 16进制的Str转Str
*
* @param hexStr
* @return
*/
public static String HexStrToStr(String hexStr)
{
//能被16整除,肯定可以被2整除
byte[] array = new byte[hexStr.length() / 2];
try
{
for (int i = 0; i < array.length; i++)
{
array[i] = (byte) (0xff & Integer.parseInt(hexStr.substring(i * 2, i * 2 + 2), 16));
}
hexStr = new String(array, "UTF-8");
}
catch (Exception e)
{
e.printStackTrace();
return "";
}
return hexStr;
}
}
服务端代码
使用InputStream对象的available()方法判断客户端的内容是否发送完毕
dataInputStream.available()
官方解释:返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。下一个调用可能是同一个线程,也可能是另一个线程。一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数。用我的大白话就是:返回剩余未读长度
import java.io.*;
import java.net.Socket;
/**
* 长连接
*/
public class ServerThread extends Thread
{
//16进制数字字符集
public static final String HEXSTRING = "0123456789ABCDEF";
//心跳超时时间
private static final int TIMEOUT = 60 * 1000;
private Socket m_socket;
//接收到数据的最新时间
private long m_lastReceiveTime = System.currentTimeMillis();
//该线程是否正在运行
private boolean m_isRuning = false;
public ServerThread(Socket socket)
{
this.m_socket = socket;
}
@Override
public void start()
{
if (m_isRuning)
{
System.out.println(">>>线程" + this.getId() + "启动失败,该线程正在执行");
return;
}
else
{
m_isRuning = true;
super.start();
}
}
@Override
public void run()
{
//字节输入流
InputStream inputStream = null;
//字节输出流
OutputStream outputStream = null;
try
{
inputStream = m_socket.getInputStream();
outputStream = m_socket.getOutputStream();
String info = "";
//按byte读
byte[] bytes = new byte[1];
while (m_isRuning)
{
//检测心跳
if (System.currentTimeMillis() - m_lastReceiveTime > TIMEOUT)
{
m_isRuning = false;
//跳出,执行finally块
break;
}
//返回下次调用可以不受阻塞地从此流读取或跳过的估计字节数,如果等于0则表示已经读完
if (inputStream.available() > 0)
{
//重置接收到数据的最新时间
m_lastReceiveTime = System.currentTimeMillis();
inputStream.read(bytes);
String tempStr = ByteArrayToHexStr(bytes) ;
info += tempStr;
//已经读完
if (inputStream.available() == 0)
{
System.out.println(">>>线程" + this.getId() + "收到:" + info);
String responseStr = "Hello";
//响应内容
String hexStr = StrToHexStr(responseStr);
hexStr = hexStr.replaceAll("0[x|X]|,","");
byte[] byteArray = HexStrToByteArray(hexStr);
outputStream.write(byteArray);
outputStream.flush();
//重置,不然每次收到的数据都会累加起来
info = "";
System.out.println(">>>线程" + this.getId() + "回应:" + responseStr);
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
//关闭资源
finally
{
System.out.println(">>>线程" + this.getId() + "的连接已断开n");
try
{
if (outputStream != null)
outputStream.close();
if (inputStream != null)
inputStream.close();
if (m_socket != null)
m_socket.close();
m_isRuning = false;
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
/**
* byte[]转16进制Str
*
* @param byteArray
*/
public static String ByteArrayToHexStr(byte[] byteArray)
{
if (byteArray == null)
{
return null;
}
char[] hexArray = HEXSTRING.toCharArray();
char[] hexChars = new char[byteArray.length * 2];
for (int i = 0; i < byteArray.length; i++)
{
int temp = byteArray[i] & 0xFF;
hexChars[i * 2] = hexArray[temp >>> 4];
hexChars[i * 2 + 1] = hexArray[temp & 0x0F];
}
return new String(hexChars);
}
/**
* Str转16进制Str
*
* @param str
* @return
*/
public static String StrToHexStr(String str)
{
//根据默认编码获取字节数组
byte[] bytes = str.getBytes();
StringBuilder stringBuilder = new StringBuilder(bytes.length * 2);
//将字节数组中每个字节拆解成2位16进制整数
for (int i = 0; i < bytes.length; i++)
{
stringBuilder.append("0x");
stringBuilder.append(HEXSTRING.charAt((bytes[i] & 0xf0) >> 4));
stringBuilder.append(HEXSTRING.charAt((bytes[i] & 0x0f) >> 0));
//去掉末尾的逗号
if (i != bytes.length - 1)
{
stringBuilder.append(",");
}
}
return stringBuilder.toString();
}
/**
* 16进制Str转byte[]
*
* @param hexStr 不带空格、不带0x、不带逗号的16进制Str,如:06EEF7F1
* @return
*/
public static byte[] HexStrToByteArray(String hexStr)
{
byte[] byteArray = new byte[hexStr.length() / 2];
for (int i = 0; i < byteArray.length; i++)
{
String subStr = hexStr.substring(2 * i, 2 * i + 2);
byteArray[i] = ((byte) Integer.parseInt(subStr, 16));
}
return byteArray;
}
}
开启服务端
import java.net.ServerSocket;
import java.net.Socket;
public class MySocketServer
{
public static void main(String[] args)
{
try
{
System.out.println(">>>服务启动,等待终端的连接n");
ServerSocket server = new ServerSocket(8888);
int count = 0;
while (true)
{
//开启监听
Socket socket = server.accept();
count++;
System.out.println(">>>开启第" + count + "次长连接...");
ServerThread thread = new ServerThread(socket);
thread.start();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
最后
以上就是灵巧发箍为你收集整理的Java的Socket实现长连接以及数据的发送和接收的全部内容,希望文章能够帮你解决Java的Socket实现长连接以及数据的发送和接收所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复