Java socket: Connection reset - java

I have browsed, searched ... and nothing sparkles to my mind!
I am running a chat type service between a server and an Android app. The client connects, the server registers the socket, and every 10 minutes the server sends to all connected devices a message.
My problem is that randomly I have a connection reset exception. I can not trace back when the problem occurs.
My server side code is:
final public class ChatRoomService {
private final static String AUTHENTICATE = "AUTHENTICATE";
private final static String BROADCAST = "BROADCAST";
private final static String DISCONNECT = "DISCONNECT";
private final static String OK = "OK";
private final static String NOK = "NK";
private final static Logger LOGGER = Logger.getLogger(ChatRoomService.class);
private ServerSocket listener = null;
#Inject
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
#Inject
private PlayerManager playerManager;
PlayerManager getPlayerManager() {
return playerManager;
}
private static HashSet<ChatRoomConnection> connections = new HashSet<ChatRoomConnection>();
public void addConnection(ChatRoomConnection c) {
synchronized(connections) {
connections.add(c);
}
}
public void removeConnection(ChatRoomConnection c) {
synchronized(connections) {
connections.remove(c);
}
}
public void startListeningToChatRoomConnection() throws IOException {
listener = new ServerSocket(9010);
try {
LOGGER.infof("startListening - Start listening on port %s", 9010);
while (true) {
ChatRoomConnection connection = new ChatRoomConnection(listener.accept(), this);
addConnection(connection);
connection.start();
}
} catch (IOException e) {
if (!listener.isClosed())
LOGGER.errorf("listenToChatRoomConnection - Connection lost during connection: %s", e.getMessage());
} finally {
if (listener != null && !listener.isClosed()) {
LOGGER.infof("listenToChatRoomConnection - Stop listening");
listener.close();
}
}
}
public void stopListeningToChatRoomConnection() throws IOException {
if (!listener.isClosed()) {
LOGGER.infof("stopListeningToChatRoomConnection - Stop listening");
listener.close();
listener = null;
// Closing all sockets
for (ChatRoomConnection connection : connections) {
connection.close();
}
// Clear up the connections list
synchronized (connections) {
connections.clear();
}
}
}
public void broadcastToChatRoomClients(Object message) {
synchronized (connections) {
// Log
LOGGER.debugf("Broadcast ChatRoom: %s - %s",
connections.size(),
message.toString());
for (ChatRoomConnection connection : connections) {
LOGGER.debugf("Broadcast ChatRoom to %s", connection.userName);
connection.publish(message);
}
}
}
private ChatRoomService() {
}
private static class ChatRoomConnection extends Thread {
private Socket socket;
private BufferedReader readerFromClient;
private PrintWriter writerToClient;
public String userName;
private ChatRoomService chatCService;
ChatRoomConnection(Socket socket, ChatRoomService chatRoomService) {
super("ChatRoomConnection");
this.socket = socket;
this.chatRoomService = chatRoomService;
}
public void run() {
try {
readerFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writerToClient = new PrintWriter(socket.getOutputStream(), true);
// 1- Authenticate the Device/ Player
writerToClient.println(ChatRoomService.AUTHENTICATE);
writerToClient.flush();
Gson gson = new Gson();
Request request = gson.fromJson(readerFromClient.readLine(), Request.class);
if (chatRoomService.getPlayerManager().isPlayerSignedIn(request.getPlayerId(), request.getSignedInOn())) {
Player player = (Player) chatRoomService.getEntityManager().find(Player.class, request.getPlayerId());
userName = player.getUsername();
LOGGER.infof("listenToChatRoomConnection - Connection established with %s", userName);
writerToClient.println(ChatRoomService.OK);
writerToClient.flush();
while (true)
if ((readerFromClient.readLine() == null) ||
(readerFromClient.readLine().startsWith(ChatRoomService.DISCONNECT)))
break;
} else {
writerToClient.println(ChatRoomService.NOK);
writerToClient.flush();
}
} catch (Exception e) {
LOGGER.errorf("listenToChatRoomConnection - Error with %s: %s", userName, e.getMessage());
e.printStackTrace();
} finally {
try {
if (!socket.isClosed()) {
LOGGER.infof("listenToChatRoomConnection - Connection closed by the client for %s", userName);
socket.close();
}
} catch (IOException e) {
LOGGER.errorf("listenToChatRoomConnection - Can not close socket: %s", e.getMessage());
e.printStackTrace();
} finally {
chatRoomService.removeConnection(this);
}
}
}
public void publish(Object message) {
if (!socket.isClosed()) {
writerToClient.println(ChatRoomService.BROADCAST);
Gson gson = new Gson();
writerToClient.println(gson.toJson(message));
}
}
public void close() {
writerToClient.println(ChatRoomService.DISCONNECT);
try {
LOGGER.infof("listenToChatRoomConnection - Connection closed by the server for %s", userName);
socket.close();
} catch (IOException e) {
LOGGER.errorf("Error when trying to close a socket: %s", e.getMessage());
e.printStackTrace();
}
}
};
}
The device code is:
public class ServerBroadcastManager {
private static final String TAG = ServerBroadcastManager.class.getName();
// Type of messages from the server
static public String AUTHENTICATE = "AUTHENTICATE";
static public String DISCONNECT = "DISCONNECT";
static public String BROADCAST = "BROADCAST";
static public String OK = "OK";
static public String NOK = "NK";
private int networkPort;
private ServerBroadcastListener broadcastListener;
private Socket networkSocket;
BufferedReader in;
PrintWriter out;
public ServerBroadcastManager(Context context, ServerBroadcastListener listener, int port) {
this.networkPort = port;
this.broadcastListener = listener;
}
public void startListening(final Context context) {
Runnable run = new Runnable() {
#Override
public void run() {
// Make connection and initialize streams
try {
networkSocket = new Socket();
networkSocket.connect(new InetSocketAddress(mydomain, networkPort), 30*1000);
in = new BufferedReader(new InputStreamReader(
networkSocket.getInputStream()));
out = new PrintWriter(networkSocket.getOutputStream(), true);
// Process all messages from server, according to the protocol.
while (true) {
String line = in.readLine();
if (line.startsWith(ServerBroadcastManager.AUTHENTICATE)) {
Request request = formatAuthenticateRequest(context);
Gson requestGson = new Gson();
out.println(requestGson.toJson(request));
out.flush();
// Waiting for confirmation back
line = in.readLine();
if (line.startsWith(ServerBroadcastManager.OK)) {
} else if (line.startsWith(ServerBroadcastManager.NOK)) {
}
} else if (line.startsWith(ServerBroadcastManager.BROADCAST)) {
Gson gson = new Gson();
#SuppressWarnings("unchecked")
LinkedHashMap<String,String> broadcast = gson.fromJson(in.readLine(), LinkedHashMap.class);
broadcastListener.processBroadcast(broadcast);
} else if (line.startsWith(ServerBroadcastManager.DISCONNECT)) {
break;
}
}
} catch (UnknownHostException e) {
Log.i(TAG, "Can not resolve hostname");
} catch (SocketTimeoutException e) {
Log.i(TAG, "Connection Timed-out");
broadcastListener.connectionFailed();
} catch (IOException e) {
Log.i(TAG, "Connection raised on exception: " + e.getMessage());
if (!networkSocket.isClosed()) {
broadcastListener.connectionLost();
}
}
}
};
Thread thread = new Thread(run);
thread.start();
}
public void stopListening() {
try {
if (networkSocket != null)
networkSocket.close();
} catch (IOException e) {
Log.i(TAG, "Exception in stopListening: " + e.getMessage());
}
}
private Request formatAuthenticateRequest(Context context) {
Request request = new Request();
SharedPreferences settings = context.getApplicationContext().getSharedPreferences(Constants.USER_DETAILS, 0);
request.setPlayerId(BigInteger.valueOf((settings.getLong(Constants.USER_DETAILS_PLAYERID, 0))));
request.setSignedInOn(settings.getLong(Constants.USER_DETAILS_SIGNEDINON, 0));
return request;
}
}
My last resort might be to move my server to another location, and see if this could not be related to my broadband router. I have notice that some of my HTTP call do not reach the server as well, though port forwarding is properly in place.
Thanks.
David.

I can't find where in your source code the server sends a message every 10 minutes to all connected clients, but I have experienced connection reset exceptions while using long-lasting WebSocket connections. I solved that problem by making sure some data (ping-pong message) was send from the client every minute.
At the time I traced the problem to my home-router which simply closed all idle connections after 5 minutes, but firewalls can exhibit the same kind of behavior. Neither server or client will notice a closed connection until data is transmitted. This is especially nasty for the client if the client is expecting data from the server - that data will simply never arrive. Therefor, make it the responsibility of the client to check if a connection is still valid (and reconnect when needed).
Since the introduction of the ping-pong message from the client every minute, I have not seen connection reset exceptions.

Related

RabbitMQ client applicaiton keeps generating new threads until it crashes

I am trying to find a bug is some RabbitMQ client code that was developed six or seven years ago. The code was modified to allow for delayed messages. It seems that connections are created to the RabbitMQ server and then never destroyed. Each exists in a separate thread so I end up with 1000's of threads. I am sure the problem is very obvious / simple - but I am having trouble seeing it. I have been looking at the exchangeDeclare method (the commented out version is from the original code which seemed to work), but I have been unable to find the default values for autoDelete and durable which are being set in the modified code. The method below in within a Spring service class. Any help, advice, guidance and pointing out huge obvious errors appreciated!
private void send(String routingKey, String message) throws Exception {
String exchange = applicationConfiguration.getAMQPExchange();
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-delayed-type", "fanout");
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("x-delay", 10000); //delay in miliseconds i.e 10secs
AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder().headers(headers);
Connection connection = null;
Channel channel = null;
try {
connection = myConnection.getConnection();
}
catch(Exception e) {
log.error("AMQP send method Exception. Unable to get connection.");
e.printStackTrace();
return;
}
try {
if (connection != null) {
log.debug(" [CORE: AMQP] Sending message with key {} : {}",routingKey, message);
channel = connection.createChannel();
// channel.exchangeDeclare(exchange, exchangeType);
channel.exchangeDeclare(exchange, "x-delayed-message", true, false, args);
// channel.basicPublish(exchange, routingKey, null, message.getBytes());
channel.basicPublish(exchange, routingKey, props.build(), message.getBytes());
}
else {
log.error("Total AMQP melt down. This should never happen!");
}
}
catch(Exception e) {
log.error("AMQP send method Exception. Unable to get send.");
e.printStackTrace();
}
finally {
channel.close();
}
}
This is the connection class
#Service
public class PersistentConnection {
private static final Logger log = LoggerFactory.getLogger(PersistentConnection.class);
private static Connection myConnection = null;
private Boolean blocked = false;
#Autowired ApplicationConfiguration applicationConfiguration;
#PreDestroy
private void destroy() {
try {
myConnection.close();
} catch (IOException e) {
log.error("Unable to close AMQP Connection.");
e.printStackTrace();
}
}
public Connection getConnection( ) {
if (myConnection == null) {
start();
}
return myConnection;
}
private void start() {
log.debug("Building AMQP Connection");
ConnectionFactory factory = new ConnectionFactory();
String ipAddress = applicationConfiguration.getAMQPHost();
String user = applicationConfiguration.getAMQPUser();
String password = applicationConfiguration.getAMQPPassword();
String virtualHost = applicationConfiguration.getAMQPVirtualHost();
String port = applicationConfiguration.getAMQPPort();
try {
factory.setUsername(user);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setPort(Integer.parseInt(port));
factory.setHost(ipAddress);
myConnection = factory.newConnection();
}
catch (Exception e) {
log.error("Unable to initialise AMQP Connection.");
e.printStackTrace();
}
myConnection.addBlockedListener(new BlockedListener() {
public void handleBlocked(String reason) throws IOException {
// Connection is now blocked
log.warn("Message Server has blocked. It may be resource limitted.");
blocked = true;
}
public void handleUnblocked() throws IOException {
// Connection is now unblocked
log.warn("Message server is unblocked.");
blocked = false;
}
});
}
public Boolean isBlocked() {
return blocked;
}
}

TCP Java Android Server / C# Windows Client Communication not working

I am currently trying to set up an App for an Android Device, which can communicate with Devices in the same Network via TCP connection. Said Devices run on Windows and therefore I created a simple C# TCP Client program to connect to the TCP Server. The connection gets established when the Server App is already running and a Client tries to connect to it. Both sides (Server/Client) confirm that the connection got established. When I send data from the server via DataOutputStream back to the client, the client confirms, that he got the message. But when I try to send data from the client and try to read it on the server via InputStreamReader the server never reacts to incoming messages.
Below lies the Java Android server code:
public class TCPServer {
public enum ServerCommands { TURN_OFF }
private static ServerSocket serverSocket;
private static final Handler HANDLER = new Handler(Looper.getMainLooper());
private static final int SERVERPORT = 5040;
private static final HashMap<InetAddress, ServerClientCommunicationThread> connectedClientThreads = new HashMap<>();
private interface OnUpdateUIListener {
void onShowStatus(String status);
}
private static OnUpdateUIListener listener;
public static void InitServer(Consumer<String> showStatus) {
listener = new OnUpdateUIListener() {
#Override
public void onShowStatus(String status) {
// Use the handler so we're not trying to update the UI from the bg thread
HANDLER.post(new Runnable(){
#Override
public void run(){
showStatus.accept(status);
}
});
}
};
Thread serverThread = new Thread(new ServerThread());
serverThread.start();
}
public static void OnStop(){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void SendMessageToClient(InetAddress clientIP, ServerCommands action){
ServerClientCommunicationThread clientThread = connectedClientThreads.get(clientIP);
listener.onShowStatus("Trying to send Data to client!");
if (clientThread != null)
clientThread.getHandler().sendEmptyMessage(action.ordinal());
}
private static class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
boolean error = false;
while (!Thread.currentThread().isInterrupted() && !error) {
try {
listener.onShowStatus("Start listening for clients!");
socket = serverSocket.accept();
listener.onShowStatus("Found client: " + socket.getInetAddress());
ClientServerCommunicationThread clientCommThread = new ClientServerCommunicationThread(socket);
new Thread(clientCommThread).start();
ServerClientCommunicationThread serverCommThread = new ServerClientCommunicationThread("CommThread", socket);
new Thread(serverCommThread).start();
connectedClientThreads.put(serverCommThread.clientSocket.getInetAddress(), serverCommThread);
} catch (Exception e) {
listener.onShowStatus("Could not establish client connection: " + e);
error = true;
}
}
}
}
private static class ServerClientCommunicationThread extends HandlerThread {
private DataOutputStream outputStream;
private Socket clientSocket;
private Handler commHandler;
public ServerClientCommunicationThread(String name, Socket clientSocket) {
super(name);
try {
this.clientSocket = clientSocket;
this.outputStream = new DataOutputStream(clientSocket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
listener.onShowStatus("ERROR: could not open ReaderStream: " + e);
}
}
#SuppressLint("HandlerLeak")
#Override
protected void onLooperPrepared(){
commHandler = new Handler(){
#Override
public void handleMessage(Message msg){
try {
outputStream.write(msg.what);
listener.onShowStatus("Sent action: " + msg.what);
outputStream.flush();
}
catch(Exception e){
listener.onShowStatus("Could not send data to client: " + clientSocket.getInetAddress() + " " + e);
}
}
};
listener.onShowStatus("Start Server Communication Thread");
}
public Handler getHandler(){
return commHandler;
}
}
private static class ClientServerCommunicationThread extends Thread {
private BufferedReader input;
private final Socket clientSocket;
public ClientServerCommunicationThread(Socket clientSocket){
super();
this.clientSocket = clientSocket;
try{
this.input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
listener.onShowStatus("ERROR: could not open ReaderStream: " + e);
}
}
#Override
public void run(){
listener.onShowStatus("Start Client Communication Thread");
boolean connectionStable = true;
while (!Thread.currentThread().isInterrupted() && connectionStable) {
try {
String read = input.readLine();
//It never reaches this debug message!
listener.onShowStatus("Received message: " + read);
} catch (IOException e) {
e.printStackTrace();
listener.onShowStatus("ERROR: could not read message: " + e);
connectionStable = false;
}
}
try {
input.close();
clientSocket.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Below lies my C# client code.
I am using the SuperSimpleTCP library for my C# code.
namespace SimpleTCPProgram
{
internal class TCPClient
{
private static SimpleTcpClient tcpClient;
private static int udpPort = 5041;
private static int tcpPort = 5040;
private static string macAddr;
enum ServerCommands { TURN_OFF = 0 }
// Main Method
static public void Main(String[] args)
{
InitTCPClient("192.168.1.4");
Console.ReadKey();
tcpClient.Send("Hello there");
Console.WriteLine("Sent data: " + tcpClient.Statistics.SentBytes.ToString());
Console.ReadKey();
}
private static void InitTCPClient(string serverIP)
{
try
{
tcpClient = new SimpleTcpClient(serverIP + ":" + tcpPort);
tcpClient.Events.Connected += Events_Connected;
tcpClient.Events.Disconnected += Events_Disconnected;
tcpClient.Events.DataReceived += Events_DataReceived;
tcpClient.Connect();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private static void Events_Connected(object sender, ConnectionEventArgs e)
{
Console.WriteLine("Connected to Server: " + e.IpPort);
}
private static void Events_Disconnected(object sender, ConnectionEventArgs e)
{
}
private static void Events_DataReceived(object sender, SuperSimpleTcp.DataReceivedEventArgs e)
{
string dataString = Encoding.UTF8.GetString(e.Data);
Console.WriteLine("Received Data: " + dataString);
ServerCommands serverCommand = (ServerCommands)int.Parse(dataString);
switch (serverCommand)
{
case ServerCommands.TURN_OFF:
var psi = new ProcessStartInfo("shutdown", "/s /t 0");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
Process.Start(psi);
break;
default:
break;
}
}
}
}
Wireshark seems to confirm that the message has been sent to the server.
It even catches a message sent back by the server to the client in response.
I am testing this on a test-router which doesn't have internet access and no firewall active.
My server app has the following permissions:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" tools:ignore="ManifestOrder"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
TLDR: My Android java server doesn't get any C# client messages sent via TCP connection.

Code of new thread after accepting the connection in TCP server isn't executed

I have the following tcp server:
public class Server {
private Connection db;
private Statement statement;
private ServerSocket socket;
public static void main(String[] args) {
Server server = new Server();
server.initializeServer();
System.out.println("Server initialized");
server.listenConnections();
}
private void initializeServer() {
try {
db = DriverManager.getConnection("jdbc:mysql://localhost:3306/courseworkschema" +
"?verifyServerCertificate=false" +
"&useSSL=false" +
"&requireSSL=false" +
"&useLegacyDatetimeCode=false" +
"&amp" +
"&serverTimezone=UTC",
"Sergei",
"12345");
statement = db.createStatement();
socket = new ServerSocket(1024);
} catch (SQLException | IOException e) {
e.printStackTrace();
}
}
private void listenConnections() {
System.out.println("Listening connections ... ");
while (true) {
try {
Socket client = socket.accept();
new Thread(() -> {
System.out.println("Client accepted");
try {
OutputStream outputStream = client.getOutputStream();
InputStream inputStream = client.getInputStream();
String clientAction;
String queryContent;
boolean flag = true;
while (flag) {
byte[] msg = new byte[100];
int k = inputStream.read(msg);
clientAction = new String(msg, 0, k);
clientAction = clientAction.trim();
msg = new byte[100];
k = inputStream.read(msg);
queryContent = new String(msg, 0, k);
queryContent = queryContent.trim();
System.out.println(clientAction);
System.out.println(queryContent);
if (clientAction.equalsIgnoreCase("END")) {
flag = false;
}
else if (clientAction.equalsIgnoreCase("LOGIN")) {
System.out.println("Login action");
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
This server is created to communicate with database. Here's the way how I try to connect to this serverL
public class LoginController {
private LoginWindow window;
private Socket socket;
private InputStream is;
private OutputStream os;
public LoginController() {
connectToServer();
}
public void logInUser(String login, String password) {
if (!login.isEmpty() && !password.isEmpty()) {
sendDataToServer("LOGIN");
sendDataToServer("");
} else {
window.showMessageDialog("Fill the fields!", JOptionPane.ERROR_MESSAGE);
}
}
public void attachView(LoginWindow window) {
this.window = window;
}
private void connectToServer() {
try {
socket = new Socket("127.0.0.1", 1024);
System.out.println("Connected");
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendDataToServer(String res) {
try {
os = socket.getOutputStream();
os.write(res.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I run the server and then client, I have such logs in server:
Server initialized
Listening connections ...
Process finished with exit code -1
So, I can't understand why server doesn't wait and accept a connection from client, but closes after initializing and listening. So, what's the matter? I will appreciate any help. Thanks in advance!
UPD
When I run my app it started to work but I found out that code in Thread block isn't executed. I even can't understand, why does it happen
In your private void listenConnections() you are creating a Thread object but you are not telling it to start after its created thus it wont execute.
Your thread creation line should look something like this:
new Thread(() -> {
//your code
}).start();
From the javadocs:
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#start()
public void start()
Causes this thread to begin execution; the Java Virtual Machine calls
the run method of this thread. The result is that two threads are
running concurrently: the current thread (which returns from the call
to the start method) and the other thread (which executes its run
method).
It is never legal to start a thread more than once. In particular, a
thread may not be restarted once it has completed execution.
Throws: IllegalThreadStateException - if the thread was already
started.
See Also: run(), stop()

In simple chat program, Server sending Arraylist of String but clients receiving old values

I wanted to create a simple game with a server and more than one clients. Server will have several Hashmaps and Arraylists. Server will broadcast these to clients, then one by one a client may modify these and send back to server and then server will broadcast updated values to all clients.
To get started, I have created Server - Client chat app. When a client sends String message to server, Server will add that String message to it's Arraylist and will broadcast that arraylist to all clients. I have used threads so that multiple clients can send messages concurrently, but I haven't applied thread-safety yet.
Lets come to the problem. for the first time when a client sends String to server, server prints it well, add to it's arraylist, then broadcasts it to all clients and all clients can see that too. But next time when client sends String message, server accepts it, adds to arraylist and broadcasts it, but this time all clients gets old arraylist ( list with only one String which was added first ). I have printed arraylist before broadcasting and it shows modified values, but at client side it shows list with one entry only.
Part of Server code
public class ServerGUI extends javax.swing.JFrame {
public static final int SERVER_PORT = 4000;
private ServerSocket ss;
ArrayList<String> al;
ArrayList<ClientHandler> clients;
public ServerGUI() {
initComponents();
setVisible(true);
al = new ArrayList<>();
clients = new ArrayList<>();
initNet();
}
private void initNet() {
Socket ds = null;
try {
ss = new ServerSocket(SERVER_PORT, 1);
while (true) {
ds = ss.accept();
clients.add(new ClientHandler(ds));
}
} catch (Exception e) {
System.out.println("shutting down server......");
}
}
class ClientHandler extends Thread {
private Socket ds;
private ObjectOutputStream out;
private ObjectInputStream in;
public ClientHandler(Socket ds) throws Exception {
this.ds = ds;
out = new ObjectOutputStream(ds.getOutputStream());
in = new ObjectInputStream(ds.getInputStream());
start();
}
public ObjectOutputStream getOut() {
return out;
}
public void run() {
try {
while (true) {
acceptData(in);
broadcastData();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Finally called. socket closed");
if (ds != null) {
try {
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private void acceptData(ObjectInputStream in) throws Exception {
System.out.println("acceptData called by " + Thread.currentThread().getName());
String s = (String) in.readObject();
al.add(s);
jta.setText(al.toString());
}
private void broadcastData() throws Exception {
System.out.println("broadcast called by " + Thread.currentThread().getName());
System.out.println("al is : \n" + al);
for (ClientHandler clnt : clients) {
clnt.getOut().writeObject(al);
clnt.getOut().flush();
}
}
Part of Client code
public class ClientGUI extends javax.swing.JFrame {
public static final int SERVER_PORT = 4000;
public static final String SERVER_IP = "127.0.0.1";
private Socket s1;
private ObjectOutputStream out;
private ObjectInputStream in;
private ArrayList<String> al;
public ClientGUI() {
initComponents();
setVisible(true);
initNet();
}
private void initNet() {
try {
s1 = new Socket(SERVER_IP, SERVER_PORT);
out = new ObjectOutputStream(s1.getOutputStream());
in = new ObjectInputStream(s1.getInputStream());
System.out.println("connected to server");
new ReadData();
} catch (Exception e) {
e.printStackTrace();
}
}
class ReadData extends Thread {
public ReadData() {
start();
}
public void run() {
System.out.println("client thread started");
try {
while (true) {
al = (ArrayList<String>) in.readObject();
System.out.println("client read completed, al is "+al);
jta.setText(al.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void textFieldActionPerformed(java.awt.event.ActionEvent evt) {
try {
out.writeObject(jtf.getText());
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
This is normal behavior. If you send the same object (your ArrayList) several times to a given ObjectOutputStream, the stream will send the full object the first time, and will only send a reference to this object the next times. This is what allows sending a graph of objects without consuming too much bandwidth, and without going into infinite loops because a references b which also references a.
To make sure the ArrayList is sent a second time, you need to call reset() on the ObjectOutputStream.

Chat Application using socket not working over Internet in Java

I am currently developing chat application working over Internet.currently my application working fine over LAN but not working over Internet.I have also used port forwarding.I have done setting in modem and forward the port to private IP address but still it's not working.I got the error that "server isn't found".Please suggest me what I have to do and tell,Am I done the correct setting in modem or not??
Below is my server code...
Server.java
import java.util.*;
import java.net.*;
import java.io.*;
class Server implements ChatConstants
{
private static Vector list;
private ServerSocket ssocket ;
private Service service;
private static Socket socket;
private boolean done=false;
private static Hashtable userTable = new Hashtable();
private static Hashtable _userList = new Hashtable();
private static Hashtable _conflist = new Hashtable();
public Server() throws UnknownHostException
{
System.out.println("Initializing...");
list=new Vector(BACKLOG);
try {
ssocket= new ServerSocket(SERVER_PORT,BACKLOG);
}
catch(Exception e) {
e.printStackTrace();
System.out.println("Inside constructor"+e);
}
start();
}
public void start() throws UnknownHostException
{
byte[] data;
int header;
Socket _socket = null;
String hostname = null;
System.out.println("Server successfully started at "
+InetAddress.getLocalHost().toString()
+" port "+SERVER_PORT);
while(!done) {
try
{
_socket=ssocket.accept();
if(_socket != null) {
synchronized(list) {
list.addElement(_socket);
}
DataInputStream dis=new DataInputStream(_socket.getInputStream());
data = new byte[MAX_MESSAGE_SIZE];
dis.read(data);
Message message = ((Message)ChatUtils.bytesToObject(data));
System.out.println("Joined client "
+message._username+" at "+message._host+"...");
synchronized(userTable) {
userTable.put(message._username,_socket);
}
addUser(message);
sendUserList(message);
writeToClients(message);
service = new Service(_socket,hostname,message._user);
}
}
catch(Exception e) {
e.printStackTrace();
System.out.println("Thread exception"+e);
try {
_socket.close();
}
catch(Exception ex) {
ex.printStackTrace();
System.out.println("ERROR CLOSING SOCKET");
}
}
}//END WHILE
}
private void addUser(Message message)
{
synchronized(_userList) {
_userList.put(message._user.toString(),message._user);
}
}
public static void updateUser(User user)
{
User myuser;
synchronized(_userList) {
_userList.put(user.toString(),user);
}
}
public static synchronized void writeToClients(Message message)
{
byte[] data;
DataOutputStream dos;
for(int count=0;count<list.size();count++) {
try {
dos=new
DataOutputStream(((Socket)list.elementAt(count)).getOutputStream());
data=ChatUtils.objectToBytes(message);
dos.write(data,0,data.length);
}
catch(Exception e) {
e.printStackTrace();
System.out.println("Output exception");
}
}//END FOR
}
public static void writeToClient(Message message)
{
Socket socket;
byte[] data;
DataOutputStream dos;
synchronized(userTable) {
try {
socket = (Socket)userTable.get(message._destination);
dos=new DataOutputStream(socket.getOutputStream());
data=ChatUtils.objectToBytes(message);
dos.write(data,0,data.length);
}
catch(Exception e) {
e.printStackTrace();
System.out.println("SEND EXCEPTION"+e);
}
}
}
public static void sendConferenceListToClient(Message message)
{
Socket socket;
byte[] data;
DataOutputStream dos;
synchronized(userTable) {
try {
Message mymessage= new Message(CONFERENCE_LIST);
Vector vector = (Vector)
_conflist.get(message._destination);
mymessage._username = message._username;
mymessage._destination = message._destination;
mymessage.userlist = vector;
socket = (Socket)userTable.get(message._username);
if(socket!=null) {
dos=new DataOutputStream(socket.getOutputStream());
data=ChatUtils.objectToBytes(mymessage);
dos.write(data,0,data.length);
}
}
catch(Exception e) {
e.printStackTrace();
System.out.println("CONFERENCE LIST EXCEPTION"+e);
}
}
}
public static void writeToPublicChat(Message message)
{
Socket socket;
byte[] data;
DataOutputStream dos;
synchronized(_conflist) {
try {
Vector svector = (Vector)_conflist.get(message._destination);
for(int cnt=0;cnt<svector.size();cnt++) {
synchronized(userTable) {
try {
socket = (Socket)userTable.get((svector.get(cnt).toString()));
if(socket!=null) {
dos=new DataOutputStream(socket.getOutputStream());
data=ChatUtils.objectToBytes(message);
dos.write(data,0,data.length);
}
}
catch(Exception e) {
e.printStackTrace();
System.out.println("PUBLIC CHAT EXCEPTION"+e);
}
}
}
} catch(Exception e){
e.printStackTrace();
System.out.println("PUBLIC EXCEPTION"+e);
}
}
}
public static void inviteToPublicChat(Vector svector,Message message)
{
Socket socket;
byte[] data;
DataOutputStream dos;
synchronized(_conflist) {
for(int cnt=0;cnt<svector.size();cnt++) {
synchronized(userTable) {
try {
socket = (Socket)userTable.get((svector.get(cnt).toString()));
if(socket != null) {
dos=new DataOutputStream(socket.getOutputStream());
data=ChatUtils.objectToBytes(message);
dos.write(data,0,data.length);
}
}
catch(Exception e) {
e.printStackTrace();
System.out.println("PUBLIC INVITE EXCEPTION"+e);
}
}
}
}
}
private void sendUserList(Message message)
{
int header=0;
String destination;
header=message._header;
destination = message._destination;
message._header = USERS_LIST;
message._destination = message._username;
message.userlist = new Vector(_userList.values());
writeToClient(message);
//Restore the headers
message._destination = destination;
message._header = header;
}
public static synchronized void removeUser(User user)
{
try {
Socket socket = (Socket)userTable.get(user.toString());
list.removeElement(socket);
_userList.remove(user.toString());
userTable.remove(user.toString());
}
catch(Exception e) {
e.printStackTrace();
System.out.println("ERROR REMOVING SOCKET "+e);
}
}
public static synchronized void processClientMessage(Message message)
{
switch(message._header) {
case CHANGE_STATUS:
updateUser(message._user);
writeToClients(message);
break;
case CLIENT_LOGOUT:
removeUser(message._user);
writeToClients(message);
break;
case CONFERENCE_CREATE:
Vector myvector = new Vector();
myvector.add(message._username);
_conflist.put(message._user.toString(),myvector);
case CONFERENCE_INVITE:
inviteToPublicChat(message.userlist,message);
break;
case CONFERENCE_JOIN:
Vector vector=null;
vector = (Vector)
_conflist.get(message._destination.toString());
vector.add(message._username);
_conflist.put(message._destination.toString(),vector);
writeToPublicChat(message);
break;
case CONFERENCE_DENY:
//_conflist.remove(message._user.toString(),message.userlist);
writeToPublicChat(message);
break;
case CONFERENCE_LEAVE:
Vector vectors =(Vector)
_conflist.get(message._destination.toString());
for(int count=0;count<vectors.size();count++) {
if(message._username.equals((vectors.elementAt(count).toString())))
vectors.remove(count);
}
if(vectors.size() != 0)
_conflist.put(message._user.toString(),vectors);
else//IF THERE ARE NO MORE USERS
_conflist.remove(message._user.toString());//DONE CONFERENCE
writeToPublicChat(message);
break;
case PUBLIC_CHAT:
writeToPublicChat(message);
break;
case CONFERENCE_LIST:
sendConferenceListToClient(message);
break;
default:
writeToClient(message);
}
}
public static void main(String args[]) throws Exception
{
Server chatserver=new Server();
}
}
//
// Service: Service class for each clients connected to server.
//
class Service implements Runnable, ChatConstants
{
private DataInputStream dis;
private Socket socket;
private boolean done=false;
private Thread thread;
private String hostname;
private User user;
public Service(Socket _socket,String _hostname,User user)
{
try {
this.socket = _socket;
this.hostname=_hostname;
this.user = user;
dis=new DataInputStream(socket.getInputStream());
thread=new Thread(this,"SERVICE");
thread.start();
}
catch(Exception e){
e.printStackTrace();
System.out.println("service constructor"+e);
}
}
public void run()
{
byte[] data;
while(!done)
{
try {
data = new byte[MAX_MESSAGE_SIZE];
dis.read(data);
Message message = ((Message)ChatUtils.bytesToObject(data));
Server.processClientMessage(message);
}
catch(Exception e) {
e.printStackTrace();
done = true;
Server.removeUser(user);
Message message = new Message(CLIENT_LOGOUT);
user.isOnline = OFFLINE;
message._user = user;
Server.writeToClients(message);
try {
socket.close();
} catch(Exception se) {
se.printStackTrace();
System.out.println("ERROR CLOSING SOCKET "+se);
}
//System.out.println("SERVICE THREAD EXCEPTION"+e);
}
}//END WHILE
}
}
Thanks in advance.
I think the
ssocket= new ServerSocket(SERVER_PORT,BACKLOG);
is making the issue. Use the version
ssocket= new ServerSocket(SERVER_PORT,BACKLOG,LOCAL_INET_ADDRESS);
and bind server to some constant local IP. Now use the port forwarding in the modem, to forward all requests to that local ip. Make sure that the firewall is not preventing you to use the port. Since firewall may allow a local networking but not to web.

Categories

Resources