I'm experiencing a weird issue, and I can't figure out what is occurring.
So basically, when I try to make a simple connection between a server and a client with an exchange of a float number (with DataInputStream and DataOutputStream), it seems that there is a fixed ping limit, exactly 40ms on three different computers with openjdk.
Furthermore, I tried to change the way I send the float number with:
outs.write(ByteBuffer.allocate(4).putFloat(3.14f).array(), 0, 4);
which is supposed to do the same thing as:
outs.writeFloat(3.14f);
and this odd ping limit surprisingly vanished!
Maybe I am doing something wrong with the following code:
client side
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.io.IOException;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.nio.ByteBuffer;
public class client {
private Socket sock;
private DataOutputStream outs;
private DataInputStream ins;
public client() throws IOException{
byte c;
sock = new Socket(InetAddress.getByName("localhost"),9998);
outs = new DataOutputStream(sock.getOutputStream());
ins = new DataInputStream(sock.getInputStream());
do{
long start = System.currentTimeMillis();
/* here is the thing */
//outs.write(ByteBuffer.allocate(4).putFloat(3.14f).array(), 0, 4); // either this outs
outs.writeFloat(3.14f); // or this one
outs.flush();
c = ins.readByte();
long stop = System.currentTimeMillis();
System.out.println("elapsed time: "+(stop-start)+"ms");
}while(c == (byte) 1);
}
public static void main(String[] args) {
try{
client client = new client();
} catch(SocketException e){
System.out.println("Socket disconnected");
} catch (IOException e) {
e.printStackTrace();
}
}
}
server
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.IOException;
import java.io.DataOutputStream;
import java.io.DataInputStream;
public class server extends Thread{
private DataOutputStream outs;
private DataInputStream ins;
public server(Socket sock) throws IOException{
System.out.println("client connected");
outs = new DataOutputStream(sock.getOutputStream());
ins = new DataInputStream(sock.getInputStream());
}
public void run(){
try{
while(true){
float f = ins.readFloat();
System.out.println("value: "+f);
outs.writeByte((byte) 1);
outs.flush();
}
} catch (IOException e) {
System.out.println("client disconnected");
}
}
public static void main(String[] args) {
try{
ServerSocket serverSock = new ServerSocket(9998);
while(true){
server server = new server(serverSock.accept());
server.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
which gives me (on localhost) with the usual writeFloat:
elapsed time: 40ms
else with write():
elapsed time: 0ms
Edit :
Apparently, it seems that Mike's answer solved the issue! No more 40ms latency with writeFloat...
Windows? Try to increase the number of bytes you send. There is (or was) a limit within the Windows TCP/IP stack, which waits for an amount of time the get get more bytes to get a full Package to send.
Related
so i'm trying to create a chess server for a chess application i wrote in java. The two classes i'm including are the main class that starts my TCPServerThreads and this class itselve.
I am able to connect two clients and for example echo their input back to them, but i have no idea, how to exchange information between these two threads. I am trying to forward Server inputs from one client towards the main class, or directly to the other client, so i can update the chess field on the client.
It's pretty much my first time working with servers, so thanks in advance for you patience.
This is my main class:
package Main;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import TCP.TCPServerThread;
public class Main {
public static final String StopCode = "STOP";
public static final int PORT = 8888;
public static int count = 0;
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
//create Server Socket
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("serverSocket created");
//accept client Sockets
while (count < 2) {
try {
socket = serverSocket.accept();
count ++;
System.out.println("socket Nr " + count + " accepted");
} catch (IOException e) {
System.out.println("I/O error: " + e);
}
// new thread for a client
new TCPServerThread(socket).start();
}
}
}
And this is the TCPServerThread:
package TCP;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import Main.Main;
public class TCPServerThread extends Thread{
Timestamp ts;
private int port = 0;
Socket socket;
public TCPServerThread(Socket clientSocket) {
this.socket = clientSocket;
}
public void run() {
InputStream is = null;
BufferedReader br = null;
DataOutputStream os = null;
try {
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
os = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
return;
}
String line;
while (true) {
try {
line = br.readLine();
if ((line == null) || line.equalsIgnoreCase("QUIT")) {
socket.close();
return;
} else {
if(line.equalsIgnoreCase("sp") && this.activeCount() == 3) {
os.writeBytes("1" + "\n\r");
os.flush();
}
os.writeBytes("Echo reply: " + line + "\n\r");
os.flush();
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
Thank you very much! I made the tcp threads implement runnable instead of extend thread. Then i added a ConnectionManager between the main and the TCPThreads which isn't static. This way i can put the manager into the TCPThreads constructor and communicate between its objects.
I am wondering how to check if a client is still connected to a server, like to see if the client has crashed, and if not, to check its ping to the server. Im adding all new clients to an ArrayList and when they crash I want to know how to remove them from the list so that I can keep things clean. Im not sure how to do this with Synchronization or if thats possible. If there is a better way too control my threads any advice is welcomed, thanks.
SERVER CODE:
package Main;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class MultiThreadedServer implements Runnable{
private static List<Thread> clients = new ArrayList<Thread>();
Socket cs;
private static ServerSocket ss;
private static int port = 25570;
MultiThreadedServer(Socket cs){
this.cs = cs;
}
public static void main(String args[]) throws Exception{
try{
ss = new ServerSocket(port);
System.out.println("Server Listening");
}catch(IOException e){
System.out.println("Port Taken");
}
while(true){
Socket newClient = ss.accept();
System.out.println(newClient.getInetAddress() + " Has Connected");
Thread client = new Thread(new MultiThreadedServer(newClient));
client.start();
clients.add(client);
System.out.println("Connected Clients: " + clients.size());
}
}
public void run(){
try{
PrintStream ps = new PrintStream(cs.getOutputStream());
ps.println("Welcome Client #" + clients.size());
}catch(IOException e){
System.out.println(e);
}
}
}
CLIENT CODE:
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client{
private static String ip = "127.0.0.1";
private static int port = 25570;
public static void main(){
Socket socket;
BufferedReader reader;
PrintWriter writer;
try {
socket = new Socket(ip,port);
BufferedReader in = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
OutputStreamWriter os = new
OutputStreamWriter(socket.getOutputStream());
PrintWriter out = new PrintWriter(os);
System.out.println(in.readLine());
} catch (UnknownHostException e) {
System.out.println("ERROR UNKNOWN");
e.printStackTrace();
} catch (IOException e) {
System.out.println("Could not connect to server!");
e.printStackTrace();
return;
}
}
}
Suppose I have 4 clients having port num 1,2,3,4 respectively and one server.
I want to make a connection between server and client and then send clients name and ipaddress to server and simple read that string on server.
In server side socket programming I have used a for loop to access respective clients on port 1,2,3,4.
Now my question is when the client on portnum 2 is not active, server should wait for 1 second and then move to next port num 3 but it is happening so server is stuck in that loop until it makes a connection to portnum 2.
I have used setSoTimeout function but still problem isn't resolved.
Kindly help me
Server Side code is
package server;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server implements Runnable {
Socket csocket;
Server(Socket csocket) {
this.csocket = csocket;
}
public static void main(String args[])
throws Exception {
for (int i=1; i<=4; i++) {
ServerSocket ssock = new ServerSocket(i);
System.out.println("Listening");
//while (true) {
Socket sock = ssock.accept();
System.out.println("Connected");
new Thread(new Server(sock)).start();
}
}
public void run() {
try {
DataInputStream dis = new DataInputStream(csocket.getInputStream());
String str=dis.readUTF();
System.out.print(str);
dis.close();
csocket.close();
}
catch (IOException e) {
System.out.println(e);
}
}
}
Client side code is
package client;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client
{
Socket s;
DataOutputStream dout;
public Client() {
while(true)
try {
s=new Socket("192.168.1.101",1);
dout= new DataOutputStream(s.getOutputStream());
java.net.InetAddress j = java.net.InetAddress.getLocalHost();
dout.writeUTF(j.getHostName()+"\t\t\t"+j.getHostAddress());
//Userinfo();
}
catch(Exception e)
{
System.out.println(e);
}
}
// public void Userinfo() throws UnknownHostException, IOException
// {
//
//
// }
public static void main(String as[])
{
new Client();
}
}
I have been making a online java game for the past months. The connection worked great over LAN(hamachi) with my local pc but not with external devices. I tried with router port fowarding (which is more interesting than hamachi) from an external PC but the connection is as slow (about 4 sec delay)...
I thought that the network algorith from my game was not effective so I created a simple program that sends via TCP/IP small packages and the result are as slow. I also tried to turn off my firewall and my antivirus, but the tests didn't show any change.
Can anyone explain me how to decrease the latency of the connection or why Java Sockets are that slow?
(I use the router Linksys model no: WRT54G, with Eclipse IDE)
Help is greatly appreciated.
Here are the logs from my testing program:
ON LOCAL PC...
trying to connect to xxx.xxx.xxx.xxx... (from router port fowarding)
Sent 10 request... (avg: 238 ms)
For 10 request, 4631 miliseconds has elapsed.
trying to connect to Phil-PC... (from hamachi local network)
Sent 10 request... (avg: 0 ms)
For 10 request, 10 miliseconds has elapsed.
ON EXTERNAL PC...
trying to connect to xxx.xxx.xxx.xxx... (from router port fowarding)
Sent 10 request... (avg: 235 ms)
For 10 request, 4418 miliseconds has elapsed.
trying to connect to Phil-PC... (from hamachi local network)
Sent 10 request... (avg: 245 ms)
For 10 request, 4808 miliseconds has elapsed.
Here's the source code
With setTcpNoDelay(true) added, it took half the time to complete 10 requests.
«For 10 request, 2136 miliseconds has elapsed.» I will try it in my game tonight or tomorrow !
package segp10039402;
import java.awt.BorderLayout;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class DebugServer {
static ServerSocket server;
public static void main(String[] args)
{
DebugServer debugServer = new DebugServer();
}
public DebugServer()
{
try
{
server = new ServerSocket(2620);
new Thread(accept).start();
createInterface();
}
catch(IOException ex)
{
JOptionPane.showMessageDialog(null,"Error: " + ex.getMessage(), "Alert", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
private void createInterface()
{
JFrame frame = new JFrame();
JLabel label = new JLabel("Server");
frame.add(label);
frame.setVisible(true);
}
private static Runnable accept = new Runnable()
{
#Override
public void run()
{
ObjectOutputStream oos;
ObjectInputStream ois;
while(true)
{
Socket socket;
try
{
System.out.println("Server is online...");
socket = server.accept();
System.out.println("New connection...");
for (int i=0; i<10;++i)
{
System.out.println("=================="+i+"======================");
//receive send
ois = new ObjectInputStream(socket.getInputStream());
long packet = (long) ois.readObject();
oos = new ObjectOutputStream(socket.getOutputStream());
System.out.println("Client ping: "+(long)(System.currentTimeMillis()-packet)+" ms");
//send
oos.writeObject(System.currentTimeMillis());
oos.flush();
//receive
ois = new ObjectInputStream(socket.getInputStream());
packet = (long) ois.readObject();
System.out.println("Server ping: "+packet+" ms");
}
}
catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e){e.printStackTrace();}
}
}
};
}
package segp10049302;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class DebugClient
{
public static Socket socket;
public final int TOTAL_REQUEST = 10;
public static void main(String[] args)
{
DebugClient debugClient = new DebugClient();
}
public DebugClient()
{
createInterface();
createConnection();
}
public void createConnection()
{
try
{
int port = 2620;
String ip = "184.163.171.xxx";
//String ip = "Phil-PC";
System.out.println("trying to connect to "+ip+"...");
socket = new Socket(ip, port);
socket.setTcpNoDelay(true);
ObjectOutputStream oos;
ObjectInputStream ois;
//send
long currentTime = System.currentTimeMillis();
for (int i=0; i<10;++i)
{
System.out.println("=================="+i+"======================");
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(System.currentTimeMillis());
oos.flush();
System.out.println("Sent current time");
//receive
ois = new ObjectInputStream(socket.getInputStream());
long incomingPacket = (long) ois.readObject();
long incomingPing = (long)(System.currentTimeMillis()-incomingPacket);
System.out.println("Client ping: "+ incomingPing+" ms");
//send
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(incomingPing);
oos.flush();
}
long totalTimeElapsed = (long)((System.currentTimeMillis()-currentTime));
System.out.println("For "+TOTAL_REQUEST+" request, "+totalTimeElapsed+" miliseconds has elapsed.");
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void createInterface()
{
JFrame frame = new JFrame();
JLabel label = new JLabel("Client");
frame.add(label);
frame.setVisible(true);
}
}
I try to create a program which is based on client/server communication.
In this program I have several clients and several servers.
At the beginning of the program some clients go up, and wait for new connections from different servers.
When the first server goes up, I want him to know who is the clients that are available in the network, and then it begins to communicate with all these clients in tcp protocol (ServerSocket).
However, if a new clients goes up, this server should know about it.
The same happens when new servers go up.
My first think, is to use multicast commnication. The client will send every 5 seconds a broadcast to the networks and the servers will listen to these messages.
My broblem is how to combine these two methods (multicast and tcp) in order to built this program.
Should I use two differnet ports one for the multicast, and one for the tcp protocol?
Is it possible to allow the server\client to listen for different communication (multicast or tcp) with treads?
I just need a litle push, and some basic code in order to begin this...
EDIT: OK, I succeeded to built a multicast comunication.
The agent goes up, and send every 5 seconds its name.
the server goes up, and receives the agent's broadcast.
If a new agent goes up, the server know about it.
The code look like this:
Agent code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Scanner;
public class Agent {
private static int portMulticasting = 1004;
private DatagramSocket socket;
private boolean broadcast = true;
private String group = "230.0.0.1"; //group address
private int delay = 5000;
public Agent(){
try{
socket = new DatagramSocket();
System.out.println("agent ready");
}
catch (SocketException e){
e.printStackTrace();
System.exit(1);
}
}
public void start(String agentName){
DatagramPacket packet;
try{
InetAddress address = InetAddress.getByName(group);
while (broadcast){
byte[] buf = new byte[256];
buf = agentName.getBytes();
packet = new DatagramPacket(buf,buf.length,address,portMulticasting);
socket.send(packet);
try{
Thread.sleep(delay);
} catch (InterruptedException e){
System.exit(0);
}
}
socket.close();
} catch (IOException e){
e.printStackTrace();
}
}
public static void main (String[] args) throws IOException {
System.out.println("Enter name of the new agent: ");
Scanner sc = new Scanner(System.in);
String agentName = sc.nextLine();
Agent agent = new Agent();
agent.start(agentName);
}
}
Server Code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Server {
public static void main(String[] args) throws IOException {
String groupIP = "230.0.0.1";
int portMulticasting = 1004;
if (args.length > 0)
groupIP = args[0];
try{
//get a multicast socket and join group
MulticastSocket socket = new MulticastSocket(portMulticasting);
InetAddress group = InetAddress.getByName(groupIP);
socket.joinGroup(group);
//get packet
DatagramPacket packet;
while (true){
byte[] buf = new byte[256];
packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);
buf = packet.getData();
int len = packet.getLength();
String received = (new String(buf)).substring(0,len);
try{
System.out.println("Agent name: " + received);
} catch (NumberFormatException e){
System.out.println("cannot interpret number");
}
}
socket.leaveGroup(group);
socket.close();
} catch (IOException e){
e.printStackTrace();
}
}
}
Now, I want that the agents continue to send broadcast every 5 seconds, but meanwhile the server begin to work with the agents (send messages, ask for information from the agents etc).