Here is my java server code:
public class CaspSocket {
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
public CaspSocket(InetAddress caspAddress, int caspPort) throws IOException {
socket = new Socket(caspAddress, caspPort);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
I use "out" to send data
out.print(1 + "|");
out.print(2 + "|");
out.print(3 + "|");
It will be received in GameMaker Studio as follows:
var in_buff = ds_map_find_value(async_load, "buffer");
test_string=buffer_read(in_buff, buffer_string);
This way everything will be put into a single string
test_string="1|2|3|"
However I want to receive the data in in a consecutive way
var in_buff = ds_map_find_value(async_load, "buffer");
test_string=buffer_read(in_buff, buffer_string);
test_string2=buffer_read(in_buff, buffer_string);
test_string3=buffer_read(in_buff, buffer_string);
to give
test_string="1|" test_string2="2|" test_string3="3|"
How do I send data from the java server in a consecutive way so that each chunk of data can be read out individually using buffer_read(in_buff, buffer_string); in GameMaker Studio
Edit:
I have read the using buffers section the problem is when I send in GameMaker Studio to the server using this:
buffer_seek(Buffer, buffer_seek_start, 0);
buffer_write(Buffer, buffer_string, string(1) + chr(10)); //chr(10) means new line
buffer_write(Buffer, buffer_string, string(2) + chr(10));
buffer_write(Buffer, buffer_string, string(3) + chr(10));
network_send_raw(Socket, Buffer, buffer_tell(Buffer));
The java server will only send back one string:
var in_buff = ds_map_find_value(async_load, "buffer");
buffer_read(in_buff, buffer_string);
I don't know how this should be send sequentially using the java server, like it can be received in GM:S:
var in_buff = ds_map_find_value(async_load, "buffer");
test_string=buffer_read(in_buff, buffer_string);
test_string2=buffer_read(in_buff, buffer_string);
test_string3=buffer_read(in_buff, buffer_string);
I will only be using buffer_string to make things easier.
The socket communication is based on the concept of streams. Streams are plain sequence of bytes and there is no way how you can control how they are sent. The actual transport is managed by the OS protocol driver and is not accessible from applicatio level. So based on the multiple conditions
out.print(1 + "|");
// some other code
out.print(2 + "|");
// some other code
out.print(3 + "|");
may be delivered in a single packet or several packets. Even flush() method will just push data to OS buffer and guarantee you nothing about the actual delivery.
So to read messages sequentially you should ether
Know their sizes and read into buffers of expected size (you may send some kind of "header" of fixed size data first which will tell the size of the "body" data next, then next "header" and so on)
Read full available content and split it in your client app using data delimeters (it your case this seem to be | character)
Related
I am trying to get a good sample program to send Google protocol buffer messages to and from Java server to c# client. I an using RabbitMQ for this purpose, but I found that RabbitMq service is not that reliable, and crashes some time. As a backup I want to use socket option in case RabbitMq is down.
I have code like this in java
ProtoBuffMessage.MessageProtBuff msgItem = clsBuilder.build();
ByteArrayOutputStream oStream = new ByteArrayOutputStream();
msgItem.writeTo(oStream);
...
...
//Send it to RabbitMQ
m_clsChannel.basicPublish(m_clsAppSettings.getRabbitMqExchangeName(), m_clsAppSettings.getRabbitMqExchangeQueue(), null, oStream.toByteArray());
on C# side I have code like this to receive and parse the data
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "direct_logs",
type: "direct");
var queueName = channel.QueueDeclare().QueueName;
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: "amr");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var routingKey = ea.RoutingKey;
Console.WriteLine(" [x] Received {0}':'{1}'",
routingKey, message);
Messaging.MessageProtBuff.Builder builder = new Messaging.MessageProtBuff.Builder();
builder.MergeFrom(body);
Messaging.MessageProtBuff data = builder.Build();
Console.WriteLine(data.Comment);
}
}
This works with RabbitMq if it is working properly. Now I want to know How do I use sockets to send the same, and receive it at C# client and reconstruct the Object. Preferably I would like to use the same ByteArrayOutputStream oStream object in java code. By converting it to byte array I can send it over the scocket and reconstruct the object at other end.
I have adapted this sample in my code:
http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
but in this tutorial they are sending strings. I want to send the byte array. How to do this at java end and how to parse the same at C# end?
I have a simple Java Socket connected to my Python socketserver.
In the client I want to send some data with size given in input: I want first sent an Integer with the size of the data and then the chunk of byte data.
This is the client:
Integer size = 1234
Socket so = new Socket("10.151.0.248", 8000);
byte[] bytes = new byte[size];
DataOutputStream out = new DataOutputStream(so.getOutputStream());
out.writeInt(size);
out.write(bytes);
From the server side I would like to read the amount of data that will arrive first and then read the stream again till everything is received; as final step I will send back an ACK to the client.
Here is the server:
def handle(self):
tot_data = []
length = self.request.recv(4)
size = struct.unpack("!i", length)[0]
while len(tot_data) < size:
data = self.request.recv(size - len(tot_data))
if not data: break
tot_data.append(data)
data = bytes(b"ACK")
# just send back the ack when transfer completed
self.request.sendall(data)
I am able to retrieve the size of the data in the server, but when I try to read the actual data from the stream, just 4 bytes are retrieved again and then the recv() remain blocked waiting for more data. I would like, first, to retrieve all the data, and then send back the ACK once the transfer is completed.
Any suggestions?
There one problem in the handle method Python side. self.request.recv returns a string (for Python 2.x, it will be bytes for Python3), and you assemble strings in an array. So the length of the array is just the number of chunks and not the number of bytes received.
You should write:
def handle(self):
tot_data = b""
length = self.request.recv(4)
size = struct.unpack("!i", length)[0]
while len(tot_data) < size:
data = self.request.recv(size - len(tot_data))
if not data: break
tot_data += data
data = bytes(b"ACK")
# just send back the ack when transfer completed
self.request.sendall(data)
My objective: send a local variable from the client program to the server program.
I have the client and server connected, and I know how to send string messages from the client to the server.
Example:
private void sendToServer(Socket clientSocket) throws IOException{
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
writer.write("You have connected to the server.");
writer.flush();
writer.close();
}
The above code works perfectly and sends a message.
But what do I do if I want to send data/variables between a client and a server?
For example what if I had a variable float a = 0.5, or a 2d integer array, etc. how would I send that from client to server or vice-versa?
I tried doing the same thing just using writer.write(a) instead, for example, but the inputs for writer.write() are limited, so I feel like I'm approaching it incorrectly.
If there is a better way for me to try to be sending variables aside from using BufferedReaders&BufferedWriters, could you let me know?
Thanks!
When dealing with java client/server communications, if you have full control over both ends and don't anticipate designs changing, you can directly perform encoding directly using Java serialization through the Object*Stream classes.
Example:
ObjectOutputStream output = new ObjectOutputStream(bufferedSocketStream);
output.writeInt(42); // Write a primitive integer
output.writeObject("Hello World"); // Write a string as an object
output.writeObject(myClass); // Write a class instance that you've implemented the "Serialize" interface
output.flush();
/* INPUT */
ObjectInputStream inputStream = new ObjectInputStream(bis);
int value = inputStream.readInt(); // Will receive 42
Object value2 = inputStream.readObject(); // Will receive "Hello World"
Object value3 = inputStream.readObject(); // Will receive your serialized class instance
(see https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html and https://docs.oracle.com/javase/8/docs/api/java/io/ObjectInputStream.html)
I've got a server written in python running twisted (twistd), and a client written in Java. The idea is that we'll be able to send Strings of encoded data between clients via this server. However, we're finding that clients never send a string to the server (it's never logged on the server as having been received). Does anyone have any ideas?
I've included the code for the client and server below.
Client:
Socket s = new Socket("localhost", 1025);
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
System.out.println("Before Read");
System.out.println(is.read());
System.out.println("After Read");
os.write("Hello from java!".getBytes());
Server:
class MyChat(basic.LineReceiver):
__opponent = None
def connectionMade(self):
print "SLOG"
self.factory.clients.append(self)
print "SLOG 1"
self.factory.notInGame.append(self)
print "SLOG 2"
while (len(self.factory.notInGame) >= 2):
x = self.factory.notInGame.pop(0)
y = self.factory.notInGame.pop(0)
x.__opponent = y
y.__opponent = x
print "SLOG FINISH YAY"
def connectionLost(self, reason):
print "SLOG Lost a client!"
self.factory.clients.remove(self)
if (self.__opponent == None):
self.factory.notInGame.remove(self)
else:
self.__opponent.__opponent = None
self.factory.notInGame.append(self.__opponent)
def lineReceived(self, data):
print "SLOG Sender data received"
if self.__opponent == None:
self.transport.write("E0") # not in game
print "SLOG E0"
return
self.__opponent.transport.write(data)
from twisted.internet import protocol
from twisted.application import service, internet
factory = protocol.ServerFactory()
factory.protocol = MyChat
factory.clients = []
factory.notInGame = []
application = service.Application("chatserver")
#internet.TCPServer(1025, factory).setServiceParent(application)
reactor.listenTCP(1025, factory)
Any help appreciated - thanks
Sam
LineReceiver accumulates data in a buffer and calls the lineReceived callback when it receives a full line. By default lines are terminated by the byte sequence "\r\n".
It looks like your Java application sends "Hello from java!". Since it does not send "\r\n" LineReceiver never decides to call lineReceived.
I was thinking about how you would read how much data you send over a Socket. For example if I made a Chat Application and then wanted to find out how much a message would take (in kilobytes or bytes), how would I measure this?
I send a message like "Hello, world!". How do I measure the amount of bandwidth that would take to send?
I know there are programs to monitor how much data is sent and received over the wire and all that, but I wanted to try and do this myself to learn some.
Wrap the socket's output stream in a CountingOutputStream:
CountingOutputStream cos = new CountingOutputStream(socket.getOutputStream());
cos.write(...);
System.out.println("wrote " + cos.getByteCount() + " bytes");
If you send raw string with no header (protocol)
For the strings you have
String hello = "Hello World";
hello.getBytes().length //size of the message
For showing progress to user when sending files you can do this
Socket s = new Socket();
//connect to the client, etc...
//supose you have 5 MB File
FileInputStream f = new FileInputStream( myLocalFile );
//declare a variable
int bytesSent = 0;
int c;
while( (c = f.read()) != -1) {
s.getOutputStream().write(c);
bytesSent++; //One more byte sent!
notifyGuiTotalBytesSent(bytesSent);
}
well, thats just a very simple implementation not using a buffer to read and send the data just for you get the idea.
the method nitify.... would show in the GUI thread (not this one) the bytesSent value