I need to merge two TCP packets into one. I wrote a socket emulator which reads a line of data from a csv file and outputs each line of data into two 99 byte binary packets every second. I now need to write another emulator that will merge these two 99 byte packets into one 198 byte packet.
This is what I put together so far and it basically forwards both 99 byte packets from one emulator and relays it to the client as two 99 byte packets. I have tried a couple different things but cannot seem to figure out how to merge the two into one 198 byte packet. Sounds simple, but i cannot wrap my head around it, suggestions will be greatly appreciated. Thanks
package PacketFuser;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class PacketFuser {
public static void main(String args[]) throws IOException{
//Start server
Socket socket = null;
final ServerSocket ss = new ServerSocket(6666);
System.out.println("Waiting on connection...");
while (ss.isBound()){
try {
socket = ss.accept();
System.out.println("Connected to port: " +socket.toString());
}
catch (IOException e){
}
//Start Client Socket
InetAddress address=InetAddress.getLocalHost();
Socket c1=null;
boolean client = false;
while (client == false){
try{
System.out.println("waiting on Emulator");
Thread.sleep(1000);
c1=new Socket(address, 31982);
client = true;
}
catch (IOException e){}
catch (InterruptedException ex) {}
}
System.out.println("Emulator Connected");
//I need to figure out here how to catch two packets and merge them into one 198 byte packets here.
DataInputStream in = new DataInputStream(s1.getInputStream());
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int pread;
byte[] p1 = new byte[99];
while ((pread = in.read(p1, 0, p1.length)) != -1 ) {
buffer.write(p1, 0, pread);
buffer.flush();
socket.getOutputStream().write(p1);
}
}
}
}
Change new byte[99] for new byte[198].
Related
I've read a few posts on how to send a picture using sockets in Python, and how to send a picture using sockets in Java, I was wanting to combine the two and send a picture from Python to Java using sockets on both ends. Most of my code is taken from the posts I read but here is the python client:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.0.12",4141))
try:
file = open("subbed.jpg", 'rb')
bytes = file.read()
print "{0:b}".format(len(bytes))
size = len(bytes)
s.sendall(size)
answer = s.recv(4096)
print "Answer = %s" %answer
if answer == 'GOT SIZE':
s.sendall(bytes)
answer = s.recv(4096)
if answer == 'GOT IMAGE' :
s.sendall("byte")
file.close()
finally:
s.close()
the code for the Java server is:
public static void main(String[] args) {
while(true) {
try (
ServerSocket server = new ServerSocket(PORT_NUMBER);
Socket client = server.accept();
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
InputStream in = client.getInputStream()) {
System.out.println("GOT CONNECTION FROM: " + client.getInetAddress().toString());
byte[] sizeAr = new byte[4];
in.read(sizeAr);
int size = ByteBuffer.wrap(sizeAr).asIntBuffer().get();
System.out.println(Integer.toBinaryString(size));
out.println("GOT SIZE");
byte[] imageAr = new byte[size];
in.read(imageAr);
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageAr));
ImageIO.write(image, "jpg", new File("C:\\myprivatelocation\\test.jpg"));
} catch (Exception ioe) {
ioe.printStackTrace();
}
}
}
The initial problem comes from sending the size I think. I'm no python expert, nor am I a Java expert, but I think what's happening is Python is sending the size as a string and Java is receiving it as a byte array and converting it to an integer, and there are some differences in the way they are stored in the two languages. Can anyone offer any assistance with this issue?
Although I would approach your problem slightly differently, the following code works:
Python Sender
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(("127.0.0.1", 8888))
with open("C:\\temp\\test-input.jpg", 'rb') as f:
content = f.read()
size = len(content)
print("File bytes:", size)
s.sendall(size.to_bytes(4, byteorder='big'))
buff = s.recv(4)
resp = int.from_bytes(buff, byteorder='big')
print("Response:", resp)
if size == resp:
s.sendall(content)
buff = s.recv(2)
print(buff)
print("Complete.")
Java Receiver
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
class Server{
public static void main(String[] args) {
int PORT_NUMBER = 8888;
try (
ServerSocket server = new ServerSocket(PORT_NUMBER);
Socket client = server.accept();
OutputStream sout = client.getOutputStream();
InputStream sin = client.getInputStream();
){
System.out.println("GOT CONNECTION FROM: " + client.getInetAddress().toString());
// Get length
byte[] size_buff = new byte[4];
sin.read(size_buff);
int size = ByteBuffer.wrap(size_buff).asIntBuffer().get();
System.out.format("Expecting %d bytes\n", size);
// Send it back (?)
sout.write(size_buff);
// Create Buffers
byte[] msg_buff = new byte[1024];
byte[] img_buff = new byte[size];
int img_offset = 0;
while(true) {
int bytes_read = sin.read(msg_buff, 0, msg_buff.length);
if(bytes_read == -1) { break; }
// Copy bytes into img_buff
System.arraycopy(msg_buff, 0, img_buff, img_offset, bytes_read);
img_offset += bytes_read;
System.out.format("Read %d / %d bytes...\n", img_offset, size);
if(img_offset >= size) { break; }
}
BufferedImage image = ImageIO.read(new ByteArrayInputStream(img_buff));
ImageIO.write(image, "jpg", new File("C:\\temp\\test-output.jpg"));
// Send "OK"
byte[] OK = new byte[] {0x4F, 0x4B};
sout.write(OK);
}
catch (IOException ioe) { ioe.printStackTrace(); }
}
}
The sender opens a socket, reads the file, and sends the receiver the length. The receiver gets the length, parses the bytes and sends it back. Upon receipt of the "confirmation", the sender then sends the file contents. The receiver will then repeatedly read 1024 byte chunks from the socket input stream, inserting the bytes into img_data. When there are no more bytes expected (or the socket is closed), the receiver will send "OK" to the sender (unconditionally) and exit. The sender will just print that "OK" (in bytes), and exit.
Some of this could be cleaned up with a ByteArrayOutputStream, but I wanted to get as close to the functionality of your code as possible.
Something is off - you should be getting some kind of error when trying to send some integer in the socket:
>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.connect(('localhost', 7777))
>>> s.sendall(len(b'some bytes'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a bytes-like object is required, not 'int'
Sockets can only send bytes, you have to convert the int object containing the size to bytes somehow, python won't do it automatically for you. Your code should fail with the error above.
In the java code you are using asIntBuffer() and Integer.toBinaryString to convert your values, in the python code you just try to send the data without converting, you should get error.
Now, to convert the int to bytes, you can use the struct module; It will convert to a binary representation used by the C language - I think that's what your java code expect
size_in_bytes = struct.pack('I', len(data_to_send))
In the same way, you should use struct.unpack to convert the bytes back to a integer object. See the documentation for more details and a table of possible conversions.
I have developing a simple client in java (I use a Windows 7 machine) to communicate with a server. The problem was that the server never understood my request. So I have analysed the communication with Wireshark and have noticed that only one byte is send in a first TCP packet, and 40ms after the remaining bytes are send in a other packet.
In fact, we communicate with binary frames, so all the frames must begin with the total length of the frame on 2 bytes. So it is normal that the server will never understand me. All my frames never exceed 10 bytes, so it's a insignificant amount of data. I know that TCP packets can be segmented, but for me it has no sense to segment a tiny frame after only one byte.
After unsuccessful hours of research, I tried casually to send bytes in a other way using write method instead of writeBytes method. Now I send all the data in only one TCP packet and the communication works fine, but I have never find the explanation. If someone knows, I will be happy to learn it.
Here is my code :
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
public class Client {
public static void main(String argv[]) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress("10.2.1.1", 1003), 1000);
DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
DataInputStream inFromServer = new DataInputStream(socket.getInputStream());
// Hexadecimal frame to send to server
String hexFrame = "0004FF9D3175";
// Build bytes frame
String bytesFrame = "";
for (int i=0; i<hexFrame.length()/2; i++) {
bytesFrame += (char) Integer.parseInt(hexFrame.substring(i*2, (i+1)*2), 16);
}
// This generates 2 TCP packets
// outToServer.writeBytes(bytesFrame);
// This generates only 1 TCP packet
outToServer.write(bytesFrame.getBytes());
// Read answer from server
hexFrame = "";
short frame_length = inFromServer.readShort();
for (int i=0; i<frame_length; i++) {
hexFrame += String.format("%2s", Integer.toHexString(inFromServer.readUnsignedByte())).replace(" ", "0");
}
System.out.println("Receive : " + hexFrame);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Neither Java nor TCP makes any guarantees about this. TCP can segment the data any way it likes, and you have no business relying on any two bytes being delivered consecutively. The problem here is really at the reading end, that makes incorrect assumptions.
In fact, we communicate with binary frames
In fact you are communicating over a byte-stream protocol. No frames, no message boundaries, nothing.
However, if you want a little more control over this you should use a BufferedOutputStream between the DataOutputStream and the socket output stream, and similarly a BufferedInputStream at the receiving end. Flush the stream when you want the data to be sent, typically just before the next read.
I have a client and a server, a classic example where trying to simulate in very simple way the http protocol. Firstly the client sends data while server prints the data and then the opposite. In the following code, either the server or client blocks, for an unknown reason.
The client sends to the server data, the server receive the data and prints it. But it just blocks after prints the data. If i close the outputstream of the client (out.close()) the client should get the server's data but instead throws IOException with the message: Socket closed.
My question is why is it blocking? Do i have to trigger the output with EOS?
CLIENT
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.io.IOException;
import java.io.*;
public class block_client_webclient
{
public static void main(String [] args)
{
try{
Socket s = new Socket("localhost", 8080);
OutputStreamWriter out = new OutputStreamWriter(s.getOutputStream());
InputStreamReader in = new InputStreamReader(s.getInputStream());
//WRITE
out.write("GET / HTTP/1.1\r\nUser-agent: Agent 2.0 Browser\r\nAccept: */*\r\nAccept-Language: en-US,en;q=0.5\r\nConnection: keep-alive\r\n\r\n");
out.flush();
out.close();
if (s.isConnected()==true && s.isClosed()==false) System.out.println("OPEN");
else System.out.println("CLOSED");
char[] bin = new char[400];
int r=0;
//READ
while((r=in.read(bin))!=-1) { System.out.println("Input data: "+r+" bytes"); System.out.print(bin); bin= new char[400]; };
System.out.println(r);
s.close();
}
catch (IOException ex) {System.out.println(ex.getMessage());}
}
}
SERVER
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.io.IOException;
import java.io.*;
public class block_server_webserver
{
public static void main(String [] args)
{
while(true)
{
try{
ServerSocket server = new ServerSocket(8080);
Socket connection = server.accept();
try{
OutputStreamWriter out = new OutputStreamWriter( connection.getOutputStream());
InputStreamReader in = new InputStreamReader( connection.getInputStream());
char[] bin = new char[400];
int r=0;
int readsofar=0;
//READ
while((r=in.read(bin))!=-1) { System.out.print(bin); bin= new char[400]; };
System.out.println("END");
//WRITE
out.write("Server: BlockServer 1.0\r\nHost: 192.168.1.1\r\n\r\n");
out.flush();
System.out.println("Just written data to "+connection.getRemoteSocketAddress());
connection.close();
} catch (IOException ex) { connection.close();}
}catch (IOException ex) {}
}
}
}
Doing out.close() results in a socket closed exception because when you close an input/output stream, the socket related to it also gets closed. That means that in your client program, you won't be able to read in after closing the socket.
First, take out out.close() Instead of checking for -1, try creating an "exit"string. If the server reads the exit string, recognize that it needs to stop being in the while loop and just break; (can be done with a simple if statement). Also, usually I would use a buffered reader, String x and readLine() instead of a char array + read().
while (true) {
in.read(bin);
if (bin[0] == '^') { // or something like that
break;
}
System.out.print(bin);
bin = new char[400];
}
Only close() streams when you are finished with the socket entirely.
The server should not wait for the socket to get closed (because, once that happens, it won't be able to write back).
Instead of reading until it returns -1 (closed), it should read to the end of request (two new lines in case of http headers), and start sending output as soon as that happens, then, possibly, close the connection to inform the client that there is no more data (in http, the connection usually stays open for a while, the client knows to stop reading after enough bytes have been received according to Content-length header).
Essentially what I'm trying to do is have a client (with an unknown IP) connect via socket to a server, and have the server send a BufferedImage back to the client every x seconds.
I understand how this can be done with a known client IP, but not with an unknown. A simple example would be awesome, thanks.
Example with known IP:
BufferedImage scr = getImage();
Socket sock = new Socket(ip, 123456); //unknown IP
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream(scr);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
bos.close();
sock.close();
Also, if anyone could show me where I could loop it to keep sending the file, that would be awesome.
I whipped up some sample server client connection. Basically you just define your server to use your localhost then port forward or open the server port depending on what your network configuration is. Thers lots of tutorials about that online. On your client you need to either know your external or internal IP address depending on where your connecting from.
This sample just uses your localhost and sends a file from your harddrive, but I wrote it specifically with the intended use of adding in any InputStream or OutputStream so you can adapt this to reading or writing an image. Most servers you will just bind your ip address to 127.0.0.1. When connection to the server outside your local network you will need to find your external IP address. You can find this on websites like whatsmyip.org.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class SendFileExample {
public static void main(String [] args) throws IOException {
System.out.print("Type 's' for server or 'c' for client: ");
char c = (char) System.in.read();
if(Character.toLowerCase(c) == 's') {
createServer();
} else if(Character.toLowerCase(c) == 'c') {
createClient();
}
}
public static void createServer() throws IOException {
// create a server to listen on port 12345
ServerSocket socket = new ServerSocket(12345, 0, InetAddress.getByName("127.0.0.1"));
System.out.println("Server started on " + socket.getInetAddress().getHostAddress() + ":" + socket.getLocalPort() + ",\nWaiting for client to connect.");
Socket clientConnection = socket.accept();
System.out.println("Client accepted from "+clientConnection.getInetAddress().getHostAddress()+", sending file");
pipeStreams(new FileInputStream(new File("c:\\from.txt")), clientConnection.getOutputStream(), 1024);
System.out.println("File sent, closing out connection");
clientConnection.close();
socket.close();
}
public static void createClient() throws IOException {
System.out.println("Connecting to server.");
Socket socket = new Socket();
// connect to an address, this is the server address (which you have to know)
socket.connect(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 12345));
// read all bytes from the socket
System.out.println("Success, retreiving file.");
pipeStreams(socket.getInputStream(), new FileOutputStream(new File("c:\\to.txt")), 1024);
System.out.println("Done, file sent. Closing connection");
socket.close();
}
/**
* writes all bytes from inputStream to outputStream
* #param source
* #param out
* #throws IOException
*/
public static void pipeStreams(java.io.InputStream source, java.io.OutputStream destination, int bufferSize) throws IOException {
// 16kb buffer
byte [] buffer = new byte[bufferSize];
int read = 0;
while((read=source.read(buffer)) != -1) {
destination.write(buffer, 0, read);
}
destination.flush();
destination.close();
source.close();
}
}
I think the cleanest way to achieve this would be to have the client connect every x seconds to the server, and pull the image from the socket's stream.
If you want the server to have the initiative, have the client connect to the server, and then keep the socket open to send images every x second. This means that the client must be ready to read the images as they come. It also means that the length of an image must be sent before it's content, since the image is not terminated by the end of the stream.
I am trying to create a p2p connection. This is a just test app that i have check but seems like it does not work over internet.
This is the java code that I am using on my pc to send a datagram to my friend:
'
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.*;
import javax.net.ssl.SSLServerSocket;
public class j2{
public static void main(String[] args) throws Exception {
InetAddress IPAddress = InetAddress.getByName("my friend's public IP");
DatagramSocket clientSocket = new DatagramSocket(3456);
System.out.println("Sending data");
String datamsg = "hello ";
byte[] sendData = datamsg.getBytes("UTF-8");
byte [] receiveData = new byte[10];
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 7890);
int i = 500;
//incase if some packets are lost
while(i-->1)
{
clientSocket.send(sendPacket);
}
System.out.println("Data sent");
System.out.println(clientSocket.isClosed());
clientSocket.close();
}
}
'
//My friend uses this app to receive a data gram:
// port 7890 is used to send data gram and create a hole. The same is used to receice data.
'
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.*;
import javax.net.ssl.SSLServerSocket;
public class j1{
public static void main(String[] args) throws Exception {
InetAddress IPAddress = InetAddress.getByName("any ip"); //does not matter as it is used to open a hole
DatagramSocket clientSocket = new DatagramSocket(7890);
System.out.println("Sending data");
String datamsg = "hello ";
byte[] sendData = datamsg.getBytes("UTF-8");
byte [] receiveData = new byte[10];
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 5000);
int i = 500;
while(i-->1)
{
clientSocket.send(sendPacket);
}
System.out.println("Data sent");
System.out.println(clientSocket.isClosed());
DatagramPacket receivePacket = new DatagramPacket(sendData, sendData.length);
clientSocket.receive(receivePacket);
System.out.println("Packet received");
String msg = new String(receivePacket.getData());
clientSocket.close();
}
}'
// I am not using a stun server as i already know my friends public ip address. We both have disabled our firewall as well.
Your approach is not the most reliable way to do NAT hole punching. At best it will "sometimes work".
Here's some suggestions:
Don't hardcode port numbers. Let your UDP socket code pick a random port number (i.e. port=0) and use a STUN server (or equivalent) to ascertain your public IP address and public port mapping for this local socket.
Use a reliable service to exchange the IP/port. Since you are just trying to get a single packet to go through, start with using a phone to verbally exchange this information could suffice.
You don't need to send 500 packets all at once. The firewall code on
the remote NAT might see this as a DOS attack and block everything.
Try sending like 1 a second.
You should be simultaneously listening and sending periodic packets at the same time
when trying to do the connectivity check that your code is doing.
(e.g. two seperate threads or periodic polling).
Don't close the socket until after connectivity is confirmed by both endpoints. As you have it now, your first program closes the socket immediately after it sends the packet burst.
Read my full answer here: https://stackoverflow.com/a/8524609/104458