I'm doing a chat application between C# clients and a java server.
I need to send a lot of sockets from the server to the client when he connects. I want to send the logs of the day. So I have all logs in a file.txt, and I send them to the new connected client.
For sending them, I have a for loop until all the logs are sent. Here is the loop:
for (String item : Logs) {
client.send("log:" + item);
}
And for the send method:
public void send(String text) {
//'os' is the: Socket.getOutputStream();
//What the server will send to the client
PrintWriter Out = new PrintWriter(os);
// 0 is the offset, not needed
Out.write(text, 0, text.length());
Out.flush();
System.out.println(text.length());
}
So until there, all works well.
Now my problem is: The output stream sends bytes length like '30', '100', '399' who is 'text.length()', and the C# client receive all sockets, but paste 2 or 3 sockets in one.
E.g: if I send with separated sockets (each line is a out.write() and out.flush() because I call the send method for each line)
(Server-side)
log:abcdefghijklmnopqrstuvwxyz123456789101112131415
log:abcdefghijklmnopqrstuvwxyz
log:abcdefghijklmnopqrstuvwxyz123456789101
log:abcdefghijklmnopqrstuvwxyz1234567891011121314151617
log:abcdefghijklmnopqrst
log:abcdefghijklmnopqrstuvwxyzyxwvu
The sockets will be at the end:
(Client-side)
log:abcdefghijklmnopqrstuvwxyz123456789101112131415log:abcdefghijklmnopqrstuvwxyzlog:abcdefghijklmnopqrstuvwxyz123456789101
log:abcdefghijklmnopqrstuvwxyz1234567891011121314151617log:abcdefghijklmnopqrst
log:abcdefghijklmnopqrstuvwxyzyxwvu
And if I check the sockets length in the server side I get like;
20
12
15
17
20
But in the client side;
32
15
37
The sum of multiples sockets put together.. (And sometimes it's 3 sockets put together, and sometimes 2, sometime 4...) I cant understand why...
Here's my Async method for receiving the sockets from the server;
private void callBack(IAsyncResult aResult)
{
String message = "";
try
{
int size = sck.EndReceiveFrom(aResult, ref ip);
if (size > 0)
{
byte[] receive = new byte[size];
receive = (byte[])aResult.AsyncState;
message = Encoding.Default.GetString(receive, 0, size);
Debug.WriteLine(message.Length);
}
byte[] buffer = new byte[1024];
//restart the async task
sck.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref ip, new AsyncCallback(callBack), buffer);
}
catch (Exception) { }
}
Where the int 'size' contains the size of the byte[] received, and here is the problem. How can I get the right sockets I sent from the server?
If I send each socket with delay in the server side (like 15ms), the client can get the sockets one by one. But only if you have a good connection. If your connection do like 200ms of latency, you will get the sockets grouped... So the problem is in the client side (I think...). The server (java) side works correctly, the flush method always send the socket!
UPDATE:
Here are my sockets;
//Global var
EndPoint ip;
public Socket sck;
//How I connect my sockets
private void connect()
{
ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), mysql.selectPort());
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
sck.Connect(ip);
}catch(Exception e) {
Debug.WriteLine(e.Message);
}
}
Related
Minecraft is a game which also can be played on multiplayer servers. Each server has its own IP and the port is for every server "25565". In generell, for this problem you should be familiar with Minecaft protocol(https://wiki.vg/Protocol#Login_Start). Even if not, I created a hyperlink where you can look for this.
My goal is to create a Minecraft Chatbot, without even open Minecraftlauncher to join any server. I know, there are already a lot of these existing, but I want to create some new commands which the client should send.
In generell, there are two big steps of the joining process when you join a Minecraft server. First, you need a connection sending a handshake (state 1) and "ping-pong". After this, you are connected to the server. This first step works very well, so I think I needn´t to show you. But the second step is the authentification of every client. Herefor I send a handshake (state 2) and then there comes my problem : I always get "java.io.EOFException" as a error message on my second step, sending my username to the Server.
try {
private String host = "hypixel.net";
socket.connect(host, 25565); //I created already a Socket called "socket"
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
DataInputStream input = new DataInputStream(socket.getInputStream()); //socket is for creating streams
byte[] handShakeMessage = createHandshakeMessageLogin(host, 25565);
writeVarInt(output, handShakeMessage.length);
output.write(handShakeMessage);
System.out.println("Send handShakeMessage!");
output.writeByte(0x01); //hopefully the right packet size
output.writeByte(0x00); //packetID
output.writeUTF("ExamplePlayer"); //sending username
}
public void writeVarInt(DataOutputStream out, int paramInt) throws IOException {
while (true) {
if ((paramInt & 0xFFFFFF80) == 0) {
out.writeByte(paramInt);
return;
}
out.writeByte(paramInt & 0x7F | 0x80);
paramInt >>>= 7;
}
}
public static byte [] createHandshakeMessageLogin(String host, int port) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream handshake = new DataOutputStream(buffer);
handshake.writeByte(0x00); //packet id for handshake
writeVarInt(handshake, 4); //protocol version
writeString(handshake, host, StandardCharsets.UTF_8);
handshake.writeShort(port); //port
writeVarInt(handshake, 2); //state (2 for login)
return buffer.toByteArray();
}
public void writeString(DataOutputStream out, String string, Charset charset) throws IOException {
byte [] bytes = string.getBytes(charset);
writeVarInt(out, bytes.length);
out.write(bytes);
}
So, as you can see quite a complicated thing I guess. If somebody could answer me, why I´m getting this error message and how to fix it i would be very very happy! Thank you
EDIT: I found a post, which helped me a lot with the connection! Java sending handshake packets to minecraft server
You're writing a packet length prefix of 1, when your packet contains the entire string "ExamplePlayer".
Instead, construct the packet like is done in the createHandshakeMessageLogin function, then send the length as a varint before sending the content of that buffer.
Here is the main method of Client program which write to OutputStream for server and then wait for the server to send back a response.
public static void main(String[] args) throws IOException
{
Scanner input = new Scanner(System.in);
InetAddress server_addr = InetAddress.getByName(AUCTIONSERVER_IP_ADDRESS);
Socket client = new Socket(server_addr, BUYER_PORT);
user = "";
OutputStream out = client.getOutputStream();
InputStream in = client.getInputStream();
while (true)
{
String a = input.nextLine(); //read command from user
out.write(a.getBytes()); //send the command to server
byte[] data = new byte[10000];
in.read(data, 0, 10000); //receive the output
}
}
The server program which can accept multiple buyer at the same time and start each Thread below
The run() method for each Thread server create
public void run()
{
try
{
OutputStream out = this.socket.getOutputStream();
InputStream in = this.socket.getInputStream();
while (true)
{
byte[] data = new byte[100];
in.read(data, 0, 100); // do something with the data
out.write(result.getBytes()); // return the output to Buyer client
}
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The client program will put something to OutputStream and server thread will read it (each client will be handled by 1 server thread) then send something back to client. Each write from client will match with one read from server and vice versa. However, when there is a special message sending from server to client (out of the cycle mentioned earlier), there is no way for client to receive it without messing up the cycle. Also, it will be stalled by input.nextLine() in client program so the client will not receive the notification unless he sends any command. Could anyone please suggest an efficient way to implement real-time notification for this problem?
I am thinking about making the server send an OutputStream to every thread, the one who actually have the notification will receive the message; the others will receive something like "-1". All the client program will check for inputStream at the beginning and handle it. However, this method seems inefficient for real server.
my question isn't about creating the connection. My question is about reading the stream in the c# code. The java android code is sending 3 parameters by DataOutputStream. the C# code get them all, but in different sockets. I mean if I have the array byte received it will be in 2 diffrent messagess. Let's see the code and it be clearly.
Java code :
private DataOutputStream out;
InetAddress serverAddr = InetAddress.getByName("192.168.43.145");
socket = new Socket(serverAddr, port);
out = new DataOutputStream(socket.getOutputStream());
// Header
out.writeByte(IDMessage); // example :IDMessageis is 1
// Data
out.writeDouble(LongX); // example :LongX is 35.4
out.writeDouble(LatY); // example :LatY is 31.5
out.flush();
and c# code reading :
// Data is the array byte received (byte[])
using (memory = new MemoryStream(data))
{
using (r = new BinaryReader(memory))
{
IDMessage = r.ReadInt32();
Long = r.ReadDouble();
Lat = r.ReadDouble();
}
}
Again: The problem is that the massage is received in 2 different byte array. I mean 1 array will be 1,0,0,0,..... and the other array in different massage will be 35.4,31.5,0,0,0,0,......
Any one have any idea why it happen? Thanks. :)
Edit : by the way it the message two, in the first massage I just need to send one parameter so it work's great by the sending and reading, in the two massage it send the 1 parameter alone and in other socket the two doubles.
Edit : The proxy code :
int k=0;
byte[] byteRecived = new byte[1024];
// Start Listeneting at the specified port
listenerForAndroid.Start();
// Now the server is running and waiting for a client connection.
sender = listenerForAndroid.AcceptSocket(); // Client Accepted
while (IsListener)
{
try
{
k = sender.Receive(byteRecived); // The server is resieved message . This line is get 2 other massages.
Header h = new Header(byteRecived);
message = MessageFactory.getMessage(h);
if (message is RequestID)
{
counterObserver ++;
SendIDMessage(sender,counterObserver);
}
message.DeSerialize(byteRecived);
message.Execute();
}
catch
{
}
I am writing a proxy server in Java.
Initially, I do (simplified)
server = new ServerSocket(5568);
incoming = server.accept();
input = incoming.getInputStream();
...
outgoing = new Socket(host, 80);
output = outgoing.getOutputStream();
output.write(inputbuffer, 0, i);
where inputbuffer is some collection of bytes received so far (I read the incoming data up until the part where I know the host header, and then open a connection to the server and send what I have so far). So server is my welcome socket, input is the data coming to my proxy from the client, and output is the data to the serve from my proxy.
Next, I want the output from the server to be written to the client in parallel with the client still possibly writing stuff to the server. So I create a separate thread to read from the client:
final InputStream finalInput = input;
final OutputStream finalOutput = output;
Thread sendingStuff = new Thread(){
public void run(){
int c;
while ((c = finalInput.read()) != -1){
finalOutput.write((byte)c);
finalOutput.flush();
}
finalInput.close();
finalOutput.close();
}
}
sendingStuff.start();
Finally, I have a different section in the main thread to read from the server and write that to the client.
InputStream reverseInput = outgoing.getInputStream();
OutputStream reverseOutput = incoming.getOutputStream();
int c;
while ((c = reverseInput.read()) != -1){
reverseOutput.write((byte)c);
reverseOutput.flush();
}
reverseInput.close();
reverseOutput.close();
What happens is I get input, and send output, but the browser spins forever and the line in the thread that's reading from the client never gets a -1 signal.
A lot of the time I get errors that say things like "invalid header name" or "your browser sent a request that the server could not understand" and I think it has to do with this problem I'm having. One time I even got an IOException: Socket Closed on the line that reads from the client.
So why isn't the client sending an EOF? And is this the right way to go about doing this?
"I think it's because my HTTP request has Connection: keep-alive. How do I handle this?"
I think maybe you can just open your socket once for one connection.
Try to have flag like isNewConnection. set it to true at first and after the connection is initiated, set it to false.
I've been trying to create a Java and C# app that would communicate together. In this case the user sends a String from the C# side, it should display on the Java console and echo back. Unfortunately, I have only been able to establish the connection, without being able to send or receive anything.
Java code snippet:
public CommunicationThreadHandler(Socket socket, CarList carList) {
this.socket = socket;
this.carList = carList;
try {
this.in = new DataInputStream(socket.getInputStream());
this.out = new DataOutputStream(socket.getOutputStream());
this.writer = new Writer(out);
} catch (IOException e) {
System.out.println("Exception when reading or receiving data!");
e.printStackTrace();
}
this.ip = socket.getRemoteSocketAddress().toString();
}
#Override
public void run() {
while (true) {
try {
Gson gson = new Gson();
String msgJson = in.readUTF();
String msg = gson.fromJson(msgJson,String.class);
System.out.println("Message from C# client: "+msg);
String reply = "Server echo: "+msg;
String replyJson = gson.toJson(reply);
out.writeUTF(replyJson);
if (msg.equals(Package.EXIT))
break;
} catch (IOException e) {
e.printStackTrace();
}
}
C# snippet:
public static void StartClient()
{
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
while (true)
{
Console.Write("Enter message to server: ");
string message = Console.ReadLine();
Console.WriteLine($"To be sent: {message}");
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes(message);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
string msgFromServer = Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (msgFromServer.Equals("EXIT"))
break;
Console.WriteLine($"Server says: {msgFromServer}");
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
Your problem is that you're using DataInputStream/DataOutputStream in Java, which use a Java-specific, XDR-like datatype serialization protocol. You are not using that protocol at your C# side.
Switching to using the raw input/output stream should be sufficient (although very brittle). However, notice that as you are sending raw bytes from C#, it will be impossible to tell for the recipient when the message is complete. It would be better to send the number of bytes of the message, followed by the actual message (this is what DataInputStream/DataOutputStream does, but it comes with additional considerations that you would need to correctly implement in your C# side, for example readUTF/writeUTF use a 'modified UTF-8' format instead of normal UTF-8).
The problem right now, is that you send raw bytes from C#, the readUTF() method reads the first two bytes as length, and then tries to read a message of that length. For example if C# sends "Hello" (encoded as 0x48, 0x65, 0x6c, 0x6c, 0x6f), then the Java side will read 0x48, 0x65 ("He") as "message length is 18533" and then tries to read 18533 bytes, while the actual remaining bytes are only 3 (the "llo"). This causes the input to block waiting for the remaining 18530 bytes, which never arrive.