Java Socket远程传递录音
-摘要
最近写基于Java CS的远程监控的程序,我想实现的功能有,远程控制电脑屏幕,并可以实现关机,重启,捕捉音频,文件上传下载,并实时远程获取键盘,鼠标的监听事件,目前还有远程鼠标键盘的交互没有完成,后面会继续研究
-学习感悟
写一个完整的远程监控系统,对于刚入门Socket的人来说,十分困难,但逐个分解功能,最后再一个个把功能点结合起来,就是一个完整的系统.这样,入手很简单,尽管结合时会发现也有点困难,但整合的过程中,你会发现问题,也会提高自己对Socketde的理解
注:
-以上只是我的个人学习经验,不喜勿喷,谢谢!
-以下,直接贴代码,代码实现了服务端录音,并实时录音传给客户端
客户端(负责实时播放录音)
package test.audio;
import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
/**
* Created by zqq3436 on 2017/3/22.
*/
public class Client extends Thread {
private ByteArrayInputStream bins;
private Socket socket;
private ObjectOutputStream out;
private DataInputStream dins;
private AudioInputStream audioInputStream;
private SourceDataLine sourceDataLine;
//初始化socket
public Client() {
try {
socket = new Socket("localhost", 9090);//localhost可修改为连接服务端的IP地址
} catch (IOException e) {
e.printStackTrace();
}
}
//入口方法,开启播放线程
public static void main(String[] args) {
Client c = new Client();
c.start();
}
//播放线程
public void run() {
int Len = 0;
try {
//初始化输入输出流
dins = new DataInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
try {
//循环读取录音,并播放
while (true) {
//读取字节数组长度
Len = dins.readInt();
//读取字节数组
byte[] iData = new byte[Len];
dins.readFully(iData);
//将字节数组放到字节数组输入流
bins = new ByteArrayInputStream(iData);
//取得录音数据的输入流
AudioFormat audioFormat = getAudioFormat();
audioInputStream = new AudioInputStream(bins,
audioFormat, Len / audioFormat.getFrameSize());
//构造音频输入流
DataLine.Info dataLineInfo = new DataLine.Info(
SourceDataLine.class, audioFormat);
sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
//打开具有指定格式的行,这样可使行获得所有所需的系统资源并变得可操作
sourceDataLine.open(audioFormat);
sourceDataLine.start();
//定义临时缓冲区数组
byte tempBuffer[] = new byte[Len];
//读取数据到缓存数据
int cnt = audioInputStream.read(tempBuffer, 0,
tempBuffer.length);
if (cnt > 0) {
//通过此源数据行将音频数据写入混频器 (播放声音)
sourceDataLine.write(tempBuffer, 0, cnt);
}
}
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
//取得AudioFormat
private AudioFormat getAudioFormat() {
//8000,11025,16000,22050,44100具有此格式的声音每秒播放或录制的样本数
float sampleRate = 16000.0F;
//8,16 每个具有此格式的声音样本中的位数
int sampleSizeInBits = 16;
//1,2使用此格式的音频信道数(单声道为 1,立体声为 2)。
int channels = 1;
//true,false可变比特率
boolean signed = true;
//true,false指示是以 big-endian 顺序还是 little-endian 顺序存储音频数据
boolean bigEndian = false;
return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
bigEndian);
}
}
服务端(负责实时录音,并传送给客户端)
package test.audio;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by zqq3436 on 2017/3/22.
*/
public class Server extends Thread {
private ServerSocket server;
private Socket socket;
private DataOutputStream out;//输出流
private AudioFormat audioFormat;
private TargetDataLine targetDataLine;
private ByteArrayOutputStream byteArrayOutputStream;
private int totaldatasize;
public Server() {
//初始化ServerSocket,开启录音线程并传送给socket
try {
server = new ServerSocket(9090);
System.out.println("wait.........");
//等待socket接入
socket = server.accept();
System.out.println("socket:" + socket);
out = new DataOutputStream(socket.getOutputStream());
// 开始录音,并传送给socket
capture();
} catch (IOException e) {
e.printStackTrace();
}
}
//入口方法
public static void main(String[] args) {
new Server();
}
//取得AudioFormat
private AudioFormat getAudioFormat() {
//8000,11025,16000,22050,44100具有此格式的声音每秒播放或录制的样本数
float sampleRate = 16000.0F;
//8,16 每个具有此格式的声音样本中的位数
int sampleSizeInBits = 16;
//1,2使用此格式的音频信道数(单声道为 1,立体声为 2)。
int channels = 1;
//true,false可变比特率
boolean signed = true;
//true,false指示是以 big-endian 顺序还是 little-endian 顺序存储音频数据
boolean bigEndian = false;
return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
}
//录音
private void capture() {
try {
//打开录音
audioFormat = getAudioFormat();
//构造数据行的信息对象
DataLine.Info dataLineInfo = new DataLine.Info(
TargetDataLine.class, audioFormat);
targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
//打开具有指定格式的行,这样可使行获得所有所需的系统资源并变得可操作
targetDataLine.open(audioFormat);
//创建独立线程进行录音
targetDataLine.start();
Thread captureThread = new Thread(new Server.CaptureThread());
captureThread.start();
} catch (Exception e) {
e.printStackTrace();
}
}
//录音线程
class CaptureThread extends Thread {
//创建临时缓冲数组
byte tempBuffer[] = new byte[10000];
public void run() {
try {
//循环录音
while (true) {
//不断创建字节数组输出流
byteArrayOutputStream = new ByteArrayOutputStream();
//读取10000个数据
int cnt = targetDataLine.read(tempBuffer, 0,
tempBuffer.length);
byte[] b;
if (cnt > 0) {
//保存该录音数据
byteArrayOutputStream.write(tempBuffer, 0, cnt);
b = byteArrayOutputStream.toByteArray();
int length = b.length;
//输出字节数组长度
out.writeInt(length);
//输出字节数组
out.write(b);
//关闭字节数组输出流
byteArrayOutputStream.close();
Thread.sleep(100);//线程休眠
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
尾注:
-此代码对网上代码有参考,若对AudioFormat 相关内容不明白,建议参考Java Sound用法,谢谢!