I need to implement a fairly simple WebSocket server in Java SE. All it needs to do is accept connections and store the respective sessions, then send a message to all connected client whenever a certain event is fired.
I cannot find a single tutorial for how to do this in regular Java SE. All of them require running with Maven, or deploying it as a WAR - which are all out of the question for this project. I need to run this as a Java SE desktop app.
The tutorials I have found show how to implement an endpoint using annotations like #OnOpen, #OnMessage, and #OnClose. However, none of them explain how to actually initialize the server. I also need to be able to specify a different port number for incoming connections.
Am I missing something? I know people have made chat apps using WebSocket, and that really should not require a web application server. I am not using Maven either, and would prefer to keep it that way for simplicity's sake.
https://github.com/TooTallNate/Java-WebSocket is a full WebSockets server and client implementation in Java SE, no enterprise/web app server needed.
Java 11 Server Code:
package org.treez.server.websocket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.bind.DatatypeConverter;;
public class WebSocketServer{
public static void main(String[] args){
int portNumber = 8000;
ServerSocket server;
try {
server = new ServerSocket(portNumber);
} catch (IOException exception) {
throw new IllegalStateException("Could not create web server", exception);
}
Socket clientSocket;
try {
clientSocket = server.accept(); //waits until a client connects
} catch (IOException waitException) {
throw new IllegalStateException("Could not wait for client connection", waitException);
}
InputStream inputStream;
try {
inputStream = clientSocket.getInputStream();
} catch (IOException inputStreamException) {
throw new IllegalStateException("Could not connect to client input stream", inputStreamException);
}
OutputStream outputStream;
try {
outputStream = clientSocket.getOutputStream();
} catch (IOException inputStreamException) {
throw new IllegalStateException("Could not connect to client input stream", inputStreamException);
}
try {
doHandShakeToInitializeWebSocketConnection(inputStream, outputStream);
} catch (UnsupportedEncodingException handShakeException) {
throw new IllegalStateException("Could not connect to client input stream", handShakeException);
}
try {
outputStream.write(encode("Hello from Server!"));
outputStream.flush();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
printInputStream(inputStream);
} catch (IOException printException) {
throw new IllegalStateException("Could not connect to client input stream", printException);
}
}
//Source for encoding and decoding:
//https://stackoverflow.com/questions/8125507/how-can-i-send-and-receive-websocket-messages-on-the-server-side
private static void printInputStream(InputStream inputStream) throws IOException {
int len = 0;
byte[] b = new byte[1024];
//rawIn is a Socket.getInputStream();
while(true){
len = inputStream.read(b);
if(len!=-1){
byte rLength = 0;
int rMaskIndex = 2;
int rDataStart = 0;
//b[0] is always text in my case so no need to check;
byte data = b[1];
byte op = (byte) 127;
rLength = (byte) (data & op);
if(rLength==(byte)126) rMaskIndex=4;
if(rLength==(byte)127) rMaskIndex=10;
byte[] masks = new byte[4];
int j=0;
int i=0;
for(i=rMaskIndex;i<(rMaskIndex+4);i++){
masks[j] = b[i];
j++;
}
rDataStart = rMaskIndex + 4;
int messLen = len - rDataStart;
byte[] message = new byte[messLen];
for(i=rDataStart, j=0; i<len; i++, j++){
message[j] = (byte) (b[i] ^ masks[j % 4]);
}
System.out.println(new String(message));
b = new byte[1024];
}
}
}
public static byte[] encode(String mess) throws IOException{
byte[] rawData = mess.getBytes();
int frameCount = 0;
byte[] frame = new byte[10];
frame[0] = (byte) 129;
if(rawData.length <= 125){
frame[1] = (byte) rawData.length;
frameCount = 2;
}else if(rawData.length >= 126 && rawData.length <= 65535){
frame[1] = (byte) 126;
int len = rawData.length;
frame[2] = (byte)((len >> 8 ) & (byte)255);
frame[3] = (byte)(len & (byte)255);
frameCount = 4;
}else{
frame[1] = (byte) 127;
int len = rawData.length;
frame[2] = (byte)((len >> 56 ) & (byte)255);
frame[3] = (byte)((len >> 48 ) & (byte)255);
frame[4] = (byte)((len >> 40 ) & (byte)255);
frame[5] = (byte)((len >> 32 ) & (byte)255);
frame[6] = (byte)((len >> 24 ) & (byte)255);
frame[7] = (byte)((len >> 16 ) & (byte)255);
frame[8] = (byte)((len >> 8 ) & (byte)255);
frame[9] = (byte)(len & (byte)255);
frameCount = 10;
}
int bLength = frameCount + rawData.length;
byte[] reply = new byte[bLength];
int bLim = 0;
for(int i=0; i<frameCount;i++){
reply[bLim] = frame[i];
bLim++;
}
for(int i=0; i<rawData.length;i++){
reply[bLim] = rawData[i];
bLim++;
}
return reply;
}
private static void doHandShakeToInitializeWebSocketConnection(InputStream inputStream, OutputStream outputStream) throws UnsupportedEncodingException {
String data = new Scanner(inputStream,"UTF-8").useDelimiter("\\r\\n\\r\\n").next();
Matcher get = Pattern.compile("^GET").matcher(data);
if (get.find()) {
Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data);
match.find();
byte[] response = null;
try {
response = ("HTTP/1.1 101 Switching Protocols\r\n"
+ "Connection: Upgrade\r\n"
+ "Upgrade: websocket\r\n"
+ "Sec-WebSocket-Accept: "
+ DatatypeConverter.printBase64Binary(
MessageDigest
.getInstance("SHA-1")
.digest((match.group(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
.getBytes("UTF-8")))
+ "\r\n\r\n")
.getBytes("UTF-8");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
outputStream.write(response, 0, response.length);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
}
}
}
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>TreezHttpServer</groupId>
<artifactId>TreezHttpServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</project>
JavaScript Client:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Client</title>
<script type="text/javascript">
var wsocket;
function connect() {
wsocket = new WebSocket("ws://localhost:8000");
wsocket.onopen = onopen;
wsocket.onmessage = onmessage;
wsocket.onclose = onclose;
}
function onopen() {
console.log("Connected!");
wsocket.send('hello from client');
}
function onmessage(event) {
console.log("Data received: " + event.data);
}
function onclose(e) {
console.log("Connection closed.");
}
window.addEventListener("load", connect, false);
</script>
</head>
<body>
</body>
</html>
Tried using Stefan's code. And currently it doesn't work well (I'm using Firefox). Websocket packets larger than 1024 bytes are being splitted into TCP segments, so reassembling is required.
Here is an updated code for reading browser packet:
private static void processResponse(InputStream inputStream, OutputStream outputStream) throws IOException {
int readPacketLength = 0;
byte[] packet = new byte[1024];
ByteArrayOutputStream packetStream = new ByteArrayOutputStream();
while(true) {
readPacketLength = inputStream.read(packet);
if(readPacketLength != -1) {
if ((packet[0] & (byte) 15) == (byte) 8) { // Disconnect packet
outputStream.write(packet, 0, readPacketLength);
// returning the same packet for client to terminate connection
outputStream.flush();
return;
}
byte messageLengthByte = 0;
int messageLength = 0;
int maskIndex = 2;
int messageStart = 0;
//b[0] is always text in my case so no need to check;
byte data = packet[1];
byte op = (byte) 127; // 0111 111
messageLengthByte = (byte) (data & op);
int totalPacketLength = 0;
if (messageLengthByte == (byte) 126 || messageLengthByte == (byte) 127) {
if (messageLengthByte == (byte) 126) {
maskIndex = 4;
// if (messageLengthInt==(byte)126), then 16-bit length is stored in packet[2] and [3]
ByteBuffer messageLength16Bit = ByteBuffer.allocateDirect(4);
messageLength16Bit.order(ByteOrder.BIG_ENDIAN);
messageLength16Bit.put((byte) 0x00);
messageLength16Bit.put((byte) 0x00);
messageLength16Bit.put(packet, 2, 2);
messageLength16Bit.flip();
messageLength = messageLength16Bit.getInt();
totalPacketLength = messageLength + 8;
} else {
maskIndex = 10;
// if (messageLengthInt==(byte)127), then 64-bit length is stored in bytes [2] to [9]. Using only 32-bit
ByteBuffer messageLength64Bit = ByteBuffer.allocateDirect(4);
messageLength64Bit.order(ByteOrder.BIG_ENDIAN);
messageLength64Bit.put(packet, 6, 4);
messageLength64Bit.flip();
messageLength = messageLength64Bit.getInt();
totalPacketLength = messageLength + 14;
}
if (readPacketLength != totalPacketLength) {
packetStream.write(packet, 0, readPacketLength);
int lastPacketLength = 0;
while (readPacketLength < totalPacketLength) {
packet = new byte[1024];
readPacketLength += lastPacketLength = inputStream.read(packet);
packetStream.write(packet, 0, lastPacketLength);
}
packet = packetStream.toByteArray();
packetStream.reset();
}
}
else { // using message length from packet[1]
messageLength = messageLengthByte;
}
byte[] masks = new byte[4];
int i=0; int j=0;
for(i = maskIndex; i < (maskIndex+4); i++) {
masks[j] = packet[i];
j++;
}
messageStart = maskIndex + 4;
byte[] message = new byte[messageLength];
for(i = messageStart, j = 0; i < readPacketLength; i++, j++){
message[j] = (byte) (packet[i] ^ masks[j % 4]);
}
System.out.println("Received message: " + new String(message));
packet = new byte[1024];
}
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.bind.DatatypeConverter;;
public class WebSocketServer{
public static void main(String[] args){
int portNumber = 8000;
ServerSocket server;
try {
server = new ServerSocket(portNumber);
} catch (IOException exception) {
throw new IllegalStateException("Could not create web server", exception);
}
Socket clientSocket;
try {
clientSocket = server.accept(); //waits until a client connects
} catch (IOException waitException) {
throw new IllegalStateException("Could not wait for client connection", waitException);
}
InputStream inputStream;
try {
inputStream = clientSocket.getInputStream();
} catch (IOException inputStreamException) {
throw new IllegalStateException("Could not connect to client input stream", inputStreamException);
}
OutputStream outputStream;
try {
outputStream = clientSocket.getOutputStream();
} catch (IOException inputStreamException) {
throw new IllegalStateException("Could not connect to client input stream", inputStreamException);
}
try {
doHandShakeToInitializeWebSocketConnection(inputStream, outputStream);
} catch (UnsupportedEncodingException handShakeException) {
throw new IllegalStateException("Could not connect to client input stream", handShakeException);
}
try {
outputStream.write(encode("Hello from Server!"));
outputStream.flush();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
printInputStream(inputStream);
} catch (IOException printException) {
throw new IllegalStateException("Could not connect to client input stream", printException);
}
}
//Source for encoding and decoding:
//https://stackoverflow.com/questions/8125507/how-can-i-send-and-receive-websocket-messages-on-the-server-side
//this will handle incoming text only up to 64K only
//it will handle multiple messages in one read and messages split over a read
private static void printInputStream(InputStream inputStream) throws IOException {
byte[] b = new byte[8000];//incoming buffer
byte[] message =null;//buffer to assemble message in
byte[] masks = new byte[4];
boolean isSplit=false;//has a message been split over a read
int length = 0; //length of message
int totalRead =0; //total read in message so far
while (true) {
int len = 0;//length of bytes read from socket
try {
len = inputStream.read(b);
} catch (IOException e) {
break;
}
if (len != -1) {
boolean more = false;
int totalLength = 0;
do {
int j = 0;
int i = 0;
if (!isSplit) {
byte rLength = 0;
int rMaskIndex = 2;
int rDataStart = 0;
// b[0] assuming text
byte data = b[1];
byte op = (byte) 127;
rLength = (byte) (data & op);
length = (int) rLength;
if (rLength == (byte) 126) {
rMaskIndex = 4;
length = Byte.toUnsignedInt(b[2]) << 8;
length += Byte.toUnsignedInt(b[3]);
} else if (rLength == (byte) 127)
rMaskIndex = 10;
for (i = rMaskIndex; i < (rMaskIndex + 4); i++) {
masks[j] = b[i];
j++;
}
rDataStart = rMaskIndex + 4;
message = new byte[length];
totalLength = length + rDataStart;
for (i = rDataStart, totalRead = 0; i<len && i < totalLength; i++, totalRead++) {
message[totalRead] = (byte) (b[i] ^ masks[totalRead % 4]);
}
}else {
for (i = 0; i<len && totalRead<length; i++, totalRead++) {
message[totalRead] = (byte) (b[i] ^ masks[totalRead % 4]);
}
totalLength=i;
}
if (totalRead<length) {
isSplit=true;
}else {
isSplit=false;
System.out.println(new String(message));
b = new byte[8000];
}
if (totalLength < len) {
more = true;
for (i = totalLength, j = 0; i < len; i++, j++)
b[j] = b[i];
len = len - totalLength;
}else
more = false;
} while (more);
} else
break;
}
}
public static byte[] encode(String mess) throws IOException{
byte[] rawData = mess.getBytes();
int frameCount = 0;
byte[] frame = new byte[10];
frame[0] = (byte) 129;
if(rawData.length <= 125){
frame[1] = (byte) rawData.length;
frameCount = 2;
}else if(rawData.length >= 126 && rawData.length <= 65535){
frame[1] = (byte) 126;
int len = rawData.length;
frame[2] = (byte)((len >> 8 ) & (byte)255);
frame[3] = (byte)(len & (byte)255);
frameCount = 4;
}else{
frame[1] = (byte) 127;
long len = rawData.length; //note an int is not big enough in java
frame[2] = (byte)((len >> 56 ) & (byte)255);
frame[3] = (byte)((len >> 48 ) & (byte)255);
frame[4] = (byte)((len >> 40 ) & (byte)255);
frame[5] = (byte)((len >> 32 ) & (byte)255);
frame[6] = (byte)((len >> 24 ) & (byte)255);
frame[7] = (byte)((len >> 16 ) & (byte)255);
frame[8] = (byte)((len >> 8 ) & (byte)255);
frame[9] = (byte)(len & (byte)255);
frameCount = 10;
}
int bLength = frameCount + rawData.length;
byte[] reply = new byte[bLength];
int bLim = 0;
for(int i=0; i<frameCount;i++){
reply[bLim] = frame[i];
bLim++;
}
for(int i=0; i<rawData.length;i++){
reply[bLim] = rawData[i];
bLim++;
}
return reply;
}
private static void doHandShakeToInitializeWebSocketConnection(InputStream inputStream, OutputStream outputStream) throws UnsupportedEncodingException {
String data = new Scanner(inputStream,"UTF-8").useDelimiter("\\r\\n\\r\\n").next();
Matcher get = Pattern.compile("^GET").matcher(data);
if (get.find()) {
Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data);
match.find();
byte[] response = null;
try {
response = ("HTTP/1.1 101 Switching Protocols\r\n"
+ "Connection: Upgrade\r\n"
+ "Upgrade: websocket\r\n"
+ "Sec-WebSocket-Accept: "
+ DatatypeConverter.printBase64Binary(
MessageDigest
.getInstance("SHA-1")
.digest((match.group(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
.getBytes("UTF-8")))
+ "\r\n\r\n")
.getBytes("UTF-8");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
outputStream.write(response, 0, response.length);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
}
}
}
This fixes issues with Stefan's answer. It can handle multiple messages in one read and messages split over a read. Also fixes an issue with using an int instead of a long in writes.
Related
I have tried to get the size of the image by .length in java.
However the original size of the image is several bytes higher than that.
What is the reason for this? Is there any code to get the original size?
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import javax.imageio.ImageIO;
public class Array {
public static void main(String argv[]) throws IOException {
String imageFile1 = "C:/Users/Desktop/4.jpg";
File file = new File(imageFile1);
BufferedImage originalImage = ImageIO.read(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage, "jpg", baos);
byte[] imageInByte = baos.toByteArray();
System.out.println("The length in bytes " + imageInByte.length);
}
}
I think it's about jpeg file header size.
If you want to get an original size when copying image file.
You can use just file copy rather then image file copy.
Or, you can make your own jpeg library, if you really want.
For just one example,
this is one of the old-style code by using java's NIO.
private static void fileCopy(String from, String to) {
FileChannel fromCh = null;
FileChannel toCh = null;
FileInputStream fin = null;
FileOutputStream fout = null;
try {
fin = new FileInputStream(new File(from));
fromCh = fin.getChannel();
fout = new FileOutputStream(new File(to));
toCh = fout.getChannel();
fromCh.transferTo(0, fin.available(), toCh);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fin != null)
try {
fin.close();
} catch (IOException e) {
}
if (fout != null)
try {
fout.close();
} catch (IOException e) {
}
}
}
You can get a file from the original file with the same size.
Check the reference site below:
https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format
I tested it the difference between two file, one is the original another is the copy one. I got an jpeg image from googling.
I modified some code form here in order to analyze the jpeg header file .
Here is the method:
final public static ImageProperties getJpegProperties(File file) throws FileNotFoundException, IOException {
BufferedInputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
// check for "magic" header
byte[] buf = new byte[2];
int count = in.read(buf, 0, 2);
if (count < 2) {
throw new RuntimeException("Not a valid Jpeg file!");
}
if ((buf[0]) != (byte) 0xFF || (buf[1]) != (byte) 0xD8) {
throw new RuntimeException("Not a valid Jpeg file!");
}
int width = 0;
int height = 0;
char[] comment = null;
boolean hasDims = false;
boolean hasComment = false;
int ch = 0;
int totalHeaderLen = 0;
while (ch != 0xDA && !(hasDims && hasComment)) {
/* Find next marker (JPEG markers begin with 0xFF) */
while (ch != 0xFF) {
ch = in.read();
}
/* JPEG markers can be padded with unlimited 0xFF's */
while (ch == 0xFF) {
ch = in.read();
}
/* Now, ch contains the value of the marker. */
int length = 256 * in.read();
length += in.read();
totalHeaderLen += length;
if (length < 2) {
throw new RuntimeException("Not a valid Jpeg file!");
}
/* Now, length contains the length of the marker. */
if (ch >= 0xC0 && ch <= 0xC3) {
in.read();
height = 256 * in.read();
height += in.read();
width = 256 * in.read();
width += in.read();
for (int foo = 0; foo < length - 2 - 5; foo++) {
in.read();
}
hasDims = true;
} else if (ch == 0xFE) {
// that's the comment marker
comment = new char[length - 2];
for (int foo = 0; foo < length - 2; foo++)
comment[foo] = (char) in.read();
hasComment = true;
} else {
// just skip marker
for (int foo = 0; foo < length - 2; foo++) {
in.read();
}
}
}
if(comment == null) comment = "no comment".toCharArray();
return (new ImageProperties(width, height, new String(comment), totalHeaderLen, "jpeg"));
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
The main method is :
public static void main(String argv[]) throws IOException {
String imageFile1 = "resource/4.jpg";
String imageFile2 = "resource/4_jpg.jpg";
//copyImage(imageFile1);
ImageProperties origin = getJpegProperties(new File(imageFile1));
ImageProperties copyed = getJpegProperties(new File(imageFile2));
System.out.println("============ Original one ===========");
System.out.println("comments(origin) : " + origin.getComments());
System.out.println("Height(origin) : " + origin.getHeight());
System.out.println("Width(origin) : " + origin.getWidth());
System.out.println("Header Length(origin) : " + origin.getHeaderLen());
//System.out.println("suffix(origin) : " + origin.getSuffix());
System.out.println();
System.out.println("============ Copy one ===========");
System.out.println("comments(copy) : " + copyed.getComments());
System.out.println("Height(copy) : " + copyed.getHeight());
System.out.println("Width(copy) : " + copyed.getWidth());
System.out.println("Header Length(copy) : " + copyed.getHeaderLen());
//System.out.println("suffix(copy) : " + copyed.getSuffix());
}
I copy the original image first using copyImage method here.
static BufferedImage copyImage(BufferedImage source) {
BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
I can see the difference of the two images in the explorer.
I got a different header size when running the program.
The output:
============ Original one ===========
comments(origin) : no comment
Height(origin) : 534
Width(origin) : 800
Header Length(origin) : 21269
============ Copy one ===========
comments(copy) : no comment
Height(copy) : 534
Width(copy) : 800
Header Length(copy) : 603
Header Length is different as you can see the result.
Here is full test code.
package stackoverflow;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class Misc {
public static void main(String argv[]) throws IOException {
String imageFile1 = "resource/4.jpg";
String imageFile2 = "resource/4_jpg.jpg";
String imageFile3 = "resource/4_org.jpg";
fileCopy(imageFile1, imageFile3);
//copyImage(imageFile1);
ImageProperties origin = getJpegProperties(new File(imageFile1));
ImageProperties copyed = getJpegProperties(new File(imageFile2));
System.out.println("============ Original one ===========");
System.out.println("comments(origin) : " + origin.getComments());
System.out.println("Height(origin) : " + origin.getHeight());
System.out.println("Width(origin) : " + origin.getWidth());
System.out.println("Header Length(origin) : " + origin.getHeaderLen());
//System.out.println("suffix(origin) : " + origin.getSuffix());
System.out.println();
System.out.println("============ Copy one ===========");
System.out.println("comments(copy) : " + copyed.getComments());
System.out.println("Height(copy) : " + copyed.getHeight());
System.out.println("Width(copy) : " + copyed.getWidth());
System.out.println("Header Length(copy) : " + copyed.getHeaderLen());
//System.out.println("suffix(copy) : " + copyed.getSuffix());
}
static class ImageProperties {
private final int width;
private final int height;
private final String comments;
private final int headerLen;
private final String suffix;
public ImageProperties(
final int width, final int height, final String comments, final int headerLen,
final String suffix)
{
this.width = width;
this.height = height;
this.comments = comments;
this.suffix = suffix;
this.headerLen = headerLen;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public String getComments() {
return comments;
}
public String getSuffix() {
return suffix;
}
public int getHeaderLen() {
return headerLen;
}
}
final public static ImageProperties getJpegProperties(File file) throws FileNotFoundException, IOException {
BufferedInputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
// check for "magic" header
byte[] buf = new byte[2];
int count = in.read(buf, 0, 2);
if (count < 2) {
throw new RuntimeException("Not a valid Jpeg file!");
}
if ((buf[0]) != (byte) 0xFF || (buf[1]) != (byte) 0xD8) {
throw new RuntimeException("Not a valid Jpeg file!");
}
int width = 0;
int height = 0;
char[] comment = null;
boolean hasDims = false;
boolean hasComment = false;
int ch = 0;
int totalHeaderLen = 0;
while (ch != 0xDA && !(hasDims && hasComment)) {
/* Find next marker (JPEG markers begin with 0xFF) */
while (ch != 0xFF) {
ch = in.read();
}
/* JPEG markers can be padded with unlimited 0xFF's */
while (ch == 0xFF) {
ch = in.read();
}
/* Now, ch contains the value of the marker. */
int length = 256 * in.read();
length += in.read();
totalHeaderLen += length;
if (length < 2) {
throw new RuntimeException("Not a valid Jpeg file!");
}
/* Now, length contains the length of the marker. */
if (ch >= 0xC0 && ch <= 0xC3) {
in.read();
height = 256 * in.read();
height += in.read();
width = 256 * in.read();
width += in.read();
for (int foo = 0; foo < length - 2 - 5; foo++) {
in.read();
}
hasDims = true;
} else if (ch == 0xFE) {
// that's the comment marker
comment = new char[length - 2];
for (int foo = 0; foo < length - 2; foo++)
comment[foo] = (char) in.read();
hasComment = true;
} else {
// just skip marker
for (int foo = 0; foo < length - 2; foo++) {
in.read();
}
}
}
if(comment == null) comment = "no comment".toCharArray();
return (new ImageProperties(width, height, new String(comment), totalHeaderLen, "jpeg"));
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
static BufferedImage copyImage(BufferedImage source) {
BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
private static void fileCopy(String from, String to) {
FileChannel fromCh = null;
FileChannel toCh = null;
FileInputStream fin = null;
FileOutputStream fout = null;
try {
fin = new FileInputStream(new File(from));
fromCh = fin.getChannel();
fout = new FileOutputStream(new File(to));
toCh = fout.getChannel();
fromCh.transferTo(0, fin.available(), toCh);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fin != null)
try {
fin.close();
} catch (IOException e) {
}
if (fout != null)
try {
fout.close();
} catch (IOException e) {
}
}
}
}
So, I think the extra information of the jpeg image skipped by the image io library in java.
I would like to get an Audio wave plot using Chart Area in JavaFX. Unfortunately, I am not clear how to do, what are the values to be extracted from the sound to assign to x-axis and y-axis?
I tried to read other posts, but I found nothing on javafx.
You can help me?
Sample Image:
Below is the code that extract the waveform .
I'm pulling out the right parameters for my scope?
How can I use it to print the graph with JavaFX?
public class SimpleWaveformExtractor implements WaveformExtractor {
private static final int DEFAULT_BUFFER_SIZE = 32768;
#Override
public double[] extract(File inputFile) {
AudioInputStream in = null;
try {
in = AudioSystem.getAudioInputStream(inputFile);
} catch (Exception e) {
System.out.println("Cannot read audio file");
return new double[0];
}
AudioFormat format = in.getFormat();
byte[] audioBytes = readBytes(in);
int[] result = null;
if (format.getSampleSizeInBits() == 16) {
int samplesLength = audioBytes.length / 2;
result = new int[samplesLength];
if (format.isBigEndian()) {
for (int i = 0; i < samplesLength; ++i) {
byte MSB = audioBytes[i * 2];
byte LSB = audioBytes[i * 2 + 1];
result[i] = MSB << 8 | (255 & LSB);
}
} else {
for (int i = 0; i < samplesLength; i += 2) {
byte LSB = audioBytes[i * 2];
byte MSB = audioBytes[i * 2 + 1];
result[i / 2] = MSB << 8 | (255 & LSB);
}
}
} else {
int samplesLength = audioBytes.length;
result = new int[samplesLength];
if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
for (int i = 0; i < samplesLength; ++i) {
result[i] = audioBytes[i];
}
} else {
for (int i = 0; i < samplesLength; ++i) {
result[i] = audioBytes[i] - 128;
}
}
}
return ArraysHelper.normalize(result);
}
private byte[] readBytes(AudioInputStream in) {
byte[] result = new byte[0];
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
try {
int bytesRead = 0;
do {
bytesRead = in.read(buffer);
result = ArrayUtils.addAll(result, buffer);
} while (bytesRead != -1);
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
this is the interface:
public interface WaveformExtractor {
double[] extract(File in);
}
This is the code that return the array of double:
private double[] extractWaveform(File file) throws IOException, UnsupportedAudioFileException {
return new WavFileExtractor().extract(file);
}
Alright so I am looking at this piece of code that is supposed to get an array of bytes which represents an image and send it piece by piece to a server. The server needs to be told when the image transmission is done, this ending message is "CLOSE". Everything works fine but unless I uncomment Thread.sleep the end message isn't sent. Also the delay needs to be quite big for some reason, 100 ms for example doesn't work. If anyone could provide an explanation for this behaviour I would be grateful since I don't have a very good understanding of java.
private class NetTask extends AsyncTask<Void, Void, Void>
{
private String ip;
private byte[] to_send;
public NetTask(String ip, byte[] to_send)
{
this.ip = ip;
this.to_send = to_send;
}
#Override
protected Void doInBackground(Void...params)
{
try {
Log.i(dTag, "" + to_send.length);
Socket sck = new Socket(ip, 1234);
DataOutputStream dOut = new DataOutputStream(sck.getOutputStream());
dOut.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(to_send.length).array());
Log.d(dTag, "" + to_send.length);
int x = 500;
int len = to_send.length;
for (int i = 0; i < len - x + 1; i += x)
dOut.write(Arrays.copyOfRange(to_send, i, i + x));
if (len % x != 0)
dOut.write(Arrays.copyOfRange(to_send, len - len % x, len));
/*try {
Thread.sleep(1000);
}
catch (Exception ex) {
Log.d(dTag, "thread sleep error");
}*/
dOut.write("CLOSE".getBytes());
dOut.flush();
dOut.close();
sck.close();
}
catch (IOException ex) {
Log.d(dTag, ex.getMessage());
}
return null;
}
}
The server is in c#, here is the code:
while (ok)
{
sck.Listen(1000);
Socket accepted = sck.Accept();
buffer = new byte[accepted.SendBufferSize];
int bytesRead = -1;
bool reading = true;
int im_size = -1;
int index = 0;
byte[] image = null;
while (reading)
{
bytesRead = accepted.Receive(buffer);
if (bytesRead == 5)
Console.WriteLine(bytesRead);
string strData = "YADA";
byte[] formatted = new byte[bytesRead];
if (bytesRead == 5)
{
for (int i = 0; i < bytesRead; i++)
{
formatted[i] = buffer[i];
}
strData = Encoding.ASCII.GetString(formatted);
}
if (strData == "CLOSE")
{
Console.WriteLine("GOT CLOSE MESSAGE");
Image im = Image.FromStream(new MemoryStream(image));
im.Save(#"D:\im1.bmp");
}
else
{
if (im_size == -1)
{
im_size = BitConverter.ToInt32(buffer, 0);
image = new byte[im_size];
Console.WriteLine(im_size);
}
else
{
for (int i = 0; i < bytesRead && index < im_size; i++)
{
image[index++] = buffer[i];
}
}
}
}
accepted.Close();
}
I have developed a java socket, but it takes too many cpu and virtual memory usages.
Can you tell me what is the problem in my code?
private void listen() {
try {
serverSocket = new ServerSocket(port);
System.out.println("Server socket listening on port: " + port);
System.out.println("Waiting for connections...");
while(true) {
// accept the connection
Socket socket = serverSocket.accept();
socket.setSoTimeout(30000);
System.out.println("Got connection");
// start processing the connection
Thread connectionManager = new Thread(new Elevator(socket, socket.getInputStream()));//new Thread(new ConnectionManager(socket, odometer));
connectionManager.start();
}
} catch (IOException exc) {
System.out.println(Listener.class.getName() + ": " + exc.getMessage());
}
}
in Elevator class I have this:
public class Elevator implements Runnable
{
private String imei;
private Socket socket;
private InputStream is;
private PrintWriter out;
private OutputStream ds;
private int packetL;
private long timestamp;
dbElevatorManipulate dbElevator;
private String[] allCards = null;
private String[] insCards = null;
private String[] upddelCards = null;
private String[] config = null;
public Elevator(Socket socket, InputStream is) {
this.socket = socket;
this.is = is;
initializeOutputStream(socket);
}
private void initializeOutputStream(Socket socket) {
try {
ds = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
out = new PrintWriter(ds, true);
}
#Override
public void run(){
int codecL = 1;
int imeiL = 16;
String codecID = "";
String imeiFromBoard = "";
byte[] codecBuffer = new byte[codecL];
byte[] imeiBuffer = new byte[imeiL];
try{
// Read codec ID.
is.read(codecBuffer, 0, codecL);
codecID = byteToString(codecBuffer);
//System.out.println("Codec ID : " + codecID);
// Read imei.
is.read(imeiBuffer, 0, imeiL);
imeiFromBoard = byteToString(imeiBuffer);
if (codecID.equals("2")) {
byte[] crc = new byte[2];
is.read(crc);
byte[] cnnpacket = new byte[codecL + imeiL];
cnnpacket[0] = codecBuffer[0];
for (int i = 1; i < cnnpacket.length; i++) {
cnnpacket[i] = imeiBuffer[i-1];
}
if(DataLayer.checksum(cnnpacket, crc))
{
try {
ds.write(1);
ds.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
else
{
try {
ds.close();
is.close();
dbElevator.disconnect();
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return;
}
}
}
catch(Exception ex)
{
System.out.println("Error: " + ex.getMessage());
}
imeiFromBoard = imeiFromBoard.substring(1, imeiFromBoard.length());
imei = imeiFromBoard;
System.out.println("got connection with imei:" + imei);
dbElevator = new dbElevatorManipulate(imei);
dbElevator.connect();
try{
while(true){
byte[] packet = new byte[1024];
int i = 0;
int byteread = is.read(packet);
if(byteread == -1) continue;
int cmdL = 1;
int dataLen = 2;
byte[] cmdBuffer = new byte[cmdL];
byte[] lengthBuffer = new byte[dataLen];
// Read and Print cmd.
cmdBuffer[0] = packet[0];
if(cmdBuffer[0] > 9 || cmdBuffer[0] < 0){
continue;
}
// Read and Print data length.
lengthBuffer[0] = packet[1];
lengthBuffer[1] = packet[2];
packetL = Integer.parseInt(DataLayer.byteToString(lengthBuffer));
// Reading a printing the packet .
byte[] packetBuffer = new byte[packetL];
int pcnt = 3;
while(packetL-- > 0)
{
packetBuffer[pcnt - 3] = packet[pcnt];
pcnt++;
}
String packetData = DataLayer.byteToString(packetBuffer);
// Reading and printing crc
int crcL = 2;
byte[] crcBuffer = new byte[crcL];
crcBuffer[0] = packet[pcnt];
crcBuffer[1] = packet[pcnt + 1];
if (DataLayer.checksum(packetBuffer, crcBuffer)) {
System.out.println("Packet: OK");
switch(cmdBuffer[0])
{
case 0:
int nrOfPackets = dbElevator.getNrOfTotalPackets();
int nCrc = DataLayer.crc16(new byte[] {(byte)nrOfPackets});
byte[] sendPacket = new byte[3];
sendPacket[0] = (byte)nrOfPackets;
sendPacket[1] = (byte)((nCrc >> 8) & 0xff); // hight byte of crc
sendPacket[2] = (byte)(nCrc & 0xff); // low byte of crc
ds.write(sendPacket);
ds.flush();
allCards = dbElevator.getTotalCards().split(",");
break;
case 1:
int PacketNo = Integer.parseInt(packetData);
if(allCards != null)
sendAllPacket(PacketNo);
break;
case 2:
int nrOfUpdPackets = dbElevator.getUpdDelCardsNo();
int updCrc = DataLayer.crc16(new byte[] {(byte)nrOfUpdPackets});
byte[] sendUpdPacket = new byte[3];
sendUpdPacket[0] = (byte)nrOfUpdPackets;
sendUpdPacket[1] = (byte)((updCrc >> 8) & 0xff); // hight byte of crc
sendUpdPacket[2] = (byte)(updCrc & 0xff); // low byte of crc
ds.write(sendUpdPacket);
ds.flush();
upddelCards = dbElevator.getUpdDelCards().split(",");
break;
case 3:
int updPacketNo = Integer.parseInt(packetData);
sendUpdDelPacket(updPacketNo);
break;
case 4:
int nrOfInsPackets = dbElevator.getInsertedCardsNo();
int insCrc = DataLayer.crc16(new byte[] {(byte)nrOfInsPackets});
byte[] sendInsPacket = new byte[3];
sendInsPacket[0] = (byte)nrOfInsPackets;
sendInsPacket[1] = (byte)((insCrc >> 8) & 0xff); // hight byte of crc
sendInsPacket[2] = (byte)(insCrc & 0xff); // low byte of crc
ds.write(sendInsPacket);
ds.flush();
insCards = dbElevator.getInsertedCards().split(",");
break;
case 5:
int insPacket = Integer.parseInt(packetData);
sendInsPacket(insPacket);
break;
case 6:
insertCheckInIntoDB(packetBuffer);
break;
case 7:
config = dbElevator.getConfig().split(",");
sendConfig(config);
break;
case 8: //log cards and close connection
try {
if(insCards != null && insCards.length > 2)
{
dbElevator.resetActionForIns(insCards);
dbElevator.LogSent_insCards(insCards);
}
if(upddelCards != null && upddelCards.length > 2)
{
dbElevator.resetActionForUpd(upddelCards);
dbElevator.LogSent_updCards(upddelCards);
}
if(allCards != null && allCards.length > 2)
{
dbElevator.resetActionForAll(allCards);
dbElevator.LogSent_allCards(allCards);
}
if(config != null && config.length > 0)
{
dbElevator.ConfigSent();
}
ds.close();
is.close();
dbElevator.disconnect();
System.out.println("database disconnected");
socket.close();
System.out.println("socket closed.");
return;
} catch (IOException e) {
e.printStackTrace();
}
break;
case 9:
int sendConfig = dbElevator.getSendConfig();
int sendConfigCRC = DataLayer.crc16(new byte[] {(byte)sendConfig});
byte[] sendConfigConfirm = new byte[3];
sendConfigConfirm[0] = (byte)sendConfig;
sendConfigConfirm[1] = (byte)((sendConfigCRC >> 8) & 0xff);
sendConfigConfirm[2] = (byte)(sendConfigCRC & 0xff);
ds.write(sendConfigConfirm);
ds.flush();
break;
}
}else{
//System.out.println("Packet: error");
ds.write(0x00);
ds.flush();
}
}
}catch(IOException e){
e.printStackTrace();
}
finally{
try {
ds.close();
System.out.println("ds closed.");
is.close();
System.out.println("is closed.");
dbElevator.disconnect();
System.out.println("db disconnected.");
socket.close();
System.out.println("socket closed.");
//break;
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
private void sendConfig(String[] config) throws IOException {
byte[] packet = new byte[16*3];
for(int c = 0, i = 0; c<32; c++)
{
if(c<16){
int temp = Integer.parseInt(config[c],2);
packet[i++] = (byte)((temp >> 8) & 0xff);
packet[i++] = (byte)(temp & 0xff);
}
else
{
packet[i++] = (byte)(Integer.parseInt(config[c]) & 0xff);
}
}
int crc = DataLayer.crc16(packet);
byte[] txPacket = new byte[3*16 + 2];
for(int i = 0; i<16*3; i++)
{
txPacket[i] = packet[i];
}
txPacket[16*3] = (byte)((crc >> 8) & 0xff);
txPacket[16*3 + 1] = (byte)((crc) & 0xff);
ds.write(txPacket);
ds.flush();
}
private void insertCheckInIntoDB(byte[] packetData){
String values = "";
try{
for(int i = 0; i<packetData.length; i+=8)
{
byte[] siteCode = new byte[1];
siteCode[0] = packetData[i];
byte[] siteNo = new byte[2];
siteNo[0] = packetData[i + 1];
siteNo[1] = packetData[i + 2];
byte[] Floor = new byte[1];
Floor[0] = (byte)(packetData[i + 3] >> 4 & 0xf);
byte[] Valide = new byte[1];
Valide[0] = (byte)(packetData[i + 3] & 0xf);
byte[] timestamp = new byte[4];
timestamp[0] = packetData[i + 4];
timestamp[1] = packetData[i + 5];
timestamp[2] = packetData[i + 6];
timestamp[3] = packetData[i + 7];
if(Long.parseLong(DataLayer.byteToString(timestamp)) < 1410000000)
{
continue;
}
values += "(" + imei + ",";
values += DataLayer.byteToString(siteCode) + ",";
values += DataLayer.byteToString(siteNo) + ",";
values += DataLayer.byteToString(Floor) + ",";
values += DataLayer.byteToString(Valide) + ",";
values += DataLayer.byteToString(timestamp) + "),";
}
values = values.substring(0, values.length()-1);
if(dbElevator.insertCheckIn(values))
{
ds.write(1);
ds.flush();
return;
}
else
{
try {
ds.write(0);
ds.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
catch(Exception ex){
try {
ds.write(0);
ds.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void sendUpdDelPacket(int updPacketNo) throws IOException {
byte[] packet = new byte[38*6];
for(int i = 0, c = 38*4*updPacketNo; i<38*6; i+=6, c+=4)
{
if(c + 3 < upddelCards.length)
{
packet[i] = (byte)Integer.parseInt(upddelCards[c]);
//System.out.println(upddelCards[c+1]);
packet[i+1] = (byte)(Integer.parseInt(upddelCards[c+1]) >> 8 & 0xff);
packet[i+2] = (byte)(Integer.parseInt(upddelCards[c+1]) & 0xff);
packet[i+3] = (byte)(Integer.parseInt(upddelCards[c+2], 2) >> 8 & 0xff);
packet[i+4] = (byte)(Integer.parseInt(upddelCards[c+2], 2) & 0xff);
packet[i + 5] = (byte)Integer.parseInt(upddelCards[c + 3]);
}
else
{
packet[i] = 0;
packet[i+1] = 0;
packet[i+2] = 0;
packet[i+3] = 0;
packet[i+4] = 0;
packet[i+5] = 0;
}
}
int crc = DataLayer.crc16(packet);
byte[] txPacket = new byte[38*6 + 2];
for(int i = 0; i<38*6; i++)
{
txPacket[i] = packet[i];
}
txPacket[38*6] = (byte)((crc >> 8) & 0xff);
txPacket[38*6 + 1] = (byte)((crc) & 0xff);
ds.write(txPacket);
ds.flush();
}
private void sendInsPacket(int packetNo) throws IOException {
byte[] packet = new byte[46*5];
for(int i = 0, c = 46*3*packetNo; i< 46*5; i+=5, c+=3)
{
if(c + 2 < insCards.length)
{
packet[i] = (byte)Integer.parseInt(insCards[c]);
packet[i+1] = (byte)(Integer.parseInt(insCards[c+1]) >> 8 & 0xff);
packet[i+2] = (byte)(Integer.parseInt(insCards[c+1]) & 0xff);
packet[i+3] = (byte)(Integer.parseInt(insCards[c+2], 2) >> 8 & 0xff);
packet[i+4] = (byte)(Integer.parseInt(insCards[c+2], 2) & 0xff);
}
else
{
packet[i] = 0;
packet[i+1] = 0;
packet[i+2] = 0;
packet[i+3] = 0;
packet[i+4] = 0;
}
}
int crc = DataLayer.crc16(packet);
byte[] txPacket = new byte[46*5 + 2];
for(int i = 0; i<46*5; i++)
{
txPacket[i] = packet[i];
}
txPacket[46*5] = (byte)((crc >> 8) & 0xff);
txPacket[46*5 + 1] = (byte)((crc) & 0xff);
ds.write(txPacket);
ds.flush();
}
private void sendAllPacket(int packetNo) throws IOException {
byte[] packet = new byte[46*5];
for(int i = 0, c = 46*3*packetNo; i< 46*5; i+=5, c+=3)
{
if(c + 2 < allCards.length)
{
packet[i] = (byte)Integer.parseInt(allCards[c]);
packet[i+1] = (byte)(Integer.parseInt(allCards[c+1]) >> 8 & 0xff);
packet[i+2] = (byte)(Integer.parseInt(allCards[c+1]) & 0xff);
packet[i+3] = (byte)(Integer.parseInt(allCards[c+2], 2) >> 8 & 0xff);
packet[i+4] = (byte)(Integer.parseInt(allCards[c+2], 2) & 0xff);
}
else
{
packet[i] = 0;
packet[i+1] = 0;
packet[i+2] = 0;
packet[i+3] = 0;
packet[i+4] = 0;
}
}
int crc = DataLayer.crc16(packet);
byte[] txPacket = new byte[46*5 + 2];
for(int i = 0; i<46*5; i++)
{
txPacket[i] = packet[i];
}
txPacket[46*5] = (byte)((crc >> 8) & 0xff);
txPacket[46*5 + 1] = (byte)((crc) & 0xff);
ds.write(txPacket);
ds.flush();
}
private static String byteToString(byte[] buffer) {
StringBuilder s = new StringBuilder();
for (byte b : buffer) {
s.append((char) b);
}
return s.toString();
}
What can I do about this problem ?
Thanks in advance.
You appear to be doing a lot of small reads directly on a socket's input stream. You should get better performance if you wrap the input stream with a buffered input stream.
The use of buffered streams is discussed in the Oracle Java Tutorial.
The output side looks a bit better. You are assembling packets, and writing them in large(er) write calls. However, I'm still suspicious of that ... and the possibility that some of the flush calls are unnecessary.
As EJP points out, your I/O code is fragile because you don't take account of the possibility that the "other end" has closed the socket. This will cause read and equivalent calls to return without reading anything.
Note that the read methods return the number of bytes (or characters) that they have read, or -1 if they detect "end of stream". Your code is completely ignoring the return value.
It is possible that this is the cause of your performance problems; e.g. if a thread is repeatedly calling read on a socket that is in "end of stream" state.
Another possible problem with your code is that your listen method is creating a brand new Thread each time an accept() call succeeds.
If you have lots of clients connecting, there will be lots of threads, and this results in lots of resource usage.
If clients don't disconnect and/or the server doesn't notice that they have disconnected, then the resources will leak, and your server will never give them back.
If you are leaking threads, and those threads are sitting idle, then they are wasting memory. (A thread stack is typically 1Mb or so.) If they are not idle (e.g. because of a bug in your read code ... like not dealing with the "end of stream" condition properly) then you will be wasting CPU too.
#chanjaster suggested using an executor with a fixed sized thread pool. This might help in a couple of respects:
It prevents the application using an unbounded number of threads.
It recycles the threads after they are no longer active ... which reduces overheads.
However, if you have a resource leakage problem, a thread pool won't cure this. Indeed, what will probably happen is that new connections just freeze. (They go into the task queue waiting for a worker thread to pick them up. And that never happens.)
I am trying to mix two WAV files.
The WAV files are available as byte arrays and I am using below code to mix the two.
byte[] byte1 , byte[] byte2
// 44 is header of wav file
for( int i = 44 ; i < byte1.length ; i++){
byte1[i] = byte1[i] + byte2[i];
}
The above code mostly works. But when the result is more than maximum wave (16 bit audio file), it has noise. How can I normalize mixed sound?
First of all, if, indeed, your audio is 16 bits, adding it byte-by-byte won't work. Other people commented on this. You can see my answer here for how to handle this problem.
using Android's AudioTrack to combine bytes of sound samples produces noise
Secondly, to "normalize" it, you'll have to find the peak first, and then scale all results to that value. That means two loops: one to find the "peak" and one to add the values, scaling to the new peak. Something like this:
//this is the raw audio data -- no header
short[] audioData1 , short[] audioData2
//find the max:
float max = 0;
for( int i = 0 ; i < audioData1.length ; i++) {
if( Math.abs( audioData1[i] + audioData2[i] ) > max )
max = Math.abs( audioData1[i] + audioData2[i] );
}
//now find the result, with scaling:
for( int i = 0 ; i < audioData1.length ; i++) {
audioData1[i] = Math.Round(Short.MAX_VALUE * ( audioData1[i] + audioData2[i] ) / max) ;
}
//normalized result in audioData1
short[] audioData1 = null;
short[] audioData2 = null;
int n = 0;
try {
DataInputStream in1;
in1 = new DataInputStream(new FileInputStream("v1.wav"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while ((n = in1.read()) != -1) {
bos.write(n);
}
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
bb.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
audioData1 = new short[sb.capacity()];
for (int i = 0; i < sb.capacity(); i++) {
audioData1[i] = sb.get(i);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
DataInputStream in1;
in1 = new DataInputStream(new FileInputStream("v2.wav"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while ((n = in1.read()) != -1) {
bos.write(n);
}
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
bb.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
audioData2= new short[sb.capacity()];
sb.get(audioData2);
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
// find the max:
float max = 0;
for (int i = 22; i < audioData1.length; i++) {
if (Math.abs(audioData1[i] + audioData2[i]) > max)
max = Math.abs(audioData1[i] + audioData2[i]);
}
System.out.println("" + (Short.MAX_VALUE - max));
int a, b, c;
// now find the result, with scaling:
for (int i = 22; i < audioData1.length; i++) {
a = audioData1[i];
b = audioData2[i];
c = Math.round(Short.MAX_VALUE * (audioData1[i] + audioData2[i])
/ max);
if (c > Short.MAX_VALUE)
c = Short.MAX_VALUE;
if (c < Short.MIN_VALUE)
c = Short.MIN_VALUE;
audioData1[i] = (short) c;
}
// to turn shorts back to bytes.
byte[] end = new byte[audioData1.length * 2];
ByteBuffer.wrap(end).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(audioData1);
try {
OutputStream out = new FileOutputStream("mixer.wav");
for (int i = 0; i < end.length; i++) {
out.write(end[i]);
out.flush();
}
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this works, thanks all for answers
short[] audioData1 = null;
short[] audioData2 = null;
int n = 0;
DataInputStream in1;
try {
in1 = new DataInputStream(new FileInputStream("audio1.wav"));
audioData1 = new short[in1.available() / 2];
ShortBuffer b1 = ShortBuffer.wrap(audioData1);
try {
while (true) {
n = in1.readShort();
b1.put((short) n);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
DataInputStream in2;
try {
in2 = new DataInputStream(new FileInputStream("audio2.wav"));
audioData2 = new short[in2.available() / 2];
ShortBuffer b2 = ShortBuffer.wrap(audioData2);
try {
while (true) {
n = in2.readShort();
b2.put((short) n);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
// find the max:
float max = 0;
for (int i = 44; i < audioData1.length; i++) {
if (Math.abs(audioData1[i] + audioData2[i]) > max)
max = Math.abs(audioData1[i] + audioData2[i]);
}
// now find the result, with scaling:
for (int i = 44; i < audioData1.length; i++) {
audioData1[i] = (short) Math.round(Short.MAX_VALUE
* (audioData1[i] + audioData2[i]) / max);
}
DataOutputStream out;
try {
out = new DataOutputStream(new FileOutputStream("mix.wav"));
for (int i = 0; i < audioData1.length; i++) {
out.writeShort(audioData1[i]);
out.flush();
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
now it is in short, it won't work because value max is 32768 (max short) and nothing changed