Multi Client Server applications, troubles with File I/O
This is a chat Server i made just for the hell if it. The clients can talk too each other through the Server, and also register their nicks and what not. You'll see what I'm talking about in the code comments.
Anyway the problem I'm having here, is in the Register() method.
***Problem****
If a client asks to register his/her nickname, the reg.txt file witch stores the registered nicks and passwords in the format of user:password, is wiped clean.
***Problem***
Now if i manually put in a user:password into the text file, the app as no problem recognizing a registered nick and asking for its password.
Pretty much every thing works except the little problem i have.
Your probably gonna hate me for putting the whole thing up, but everything in this source file is connected so i feel its neccessay.
I put on some very discripted comments to ease the confusion.
I Believe the problem exist in the ChatServer.Register(int clientnum, String pass) function.
Le Code:
Code:
import java.io.*;
import java.net.*;
//****************************<ChatServer>****************************
//ChatServer, a multi client to server to client chat server.
//ChatServer accepts a client, put its socket and I/O handlers arrays specified
//and puts the client's I/O handlers into the Listener Thread.
//The thread listens for the input, and uses ChatServers SendOut method to send to all clients if no command is specified
//all of ChatServers method must include the clientnum, that is the array index in clients[], out[], in[], and clientid[].
//***************************</ChatServer>*****************************
public class ChatServer {
//These arrays are for the incomeing Sockets and thier I/O handlers
public static Socket clients[] = new Socket[200];
public static PrintWriter out[] = new PrintWriter[200];
public static BufferedReader in[] = new BufferedReader[200];
//Read the file reg.txt to see if nick is registered, and print to file if client registers nick
public static BufferedReader filein = new BufferedReader(new FileReader("reg.txt"));
public static PrintWriter fileout = new PrintWriter(new FileWriter("reg.txt"));
//Arrays for client's nicks
public static String clientid[] = new String[200];
public static String registered[] = new String[200];
public static String password[] = new String[200];
//i is for handling incoming connections and assigning client to clientnum, port is obvious.
public static int i=0;
public static int port;
public ChatServer() {}
public ChatServer(int bind) throws IOException {
port = bind;
}
public void Start() throws IOException {
//invoked in main()
ServerSocket server = new ServerSocket(port);
int j;
//The infinite loop to accept clients;
while(true) {
//if over 200 logins, kill server
if(i >= 200) {
for(j=0; j<clients.length; j++) {
if(clients[j] != null) {
out[j].println("Server Time out");
System.exit(0);
}
}
}
//accept client, transport clients number over to Handle, and inc i.
clients[i] = server.accept();
Handle(i);
i++;
}
}
public void Handle(int clientnum) throws IOException {
//invoked in Start();
//set up clients I/O
out[clientnum] = new PrintWriter(clients[clientnum].getOutputStream(), true);
in[clientnum] = new BufferedReader(new InputStreamReader(clients[clientnum].getInputStream()));
ChatServer self = new ChatServer();
//Make new Listener Thread with clients I/O hanlders and clients number, and blank copy of ChatServer.
new Thread(new Listener(self, in[clientnum], out[clientnum], clientnum)).start();
}
public void Welcome(int clientnum, String user) throws IOException {
//invoked in Listener.run();
String pass;
boolean reged = false;
int j=0;
String l;
//Read the reg.txt file and put contents into register arrays
while(true) {
l = filein.readLine();
if(l != null) {
//line looks like this..username:password..split them, put the username into register[] and password into password[]
String ls[] = l.split(":");
registered[j] = ls[0];
password[j] = ls[1];
j++;
} else {
break;
}
}
file.close();
//check to see if the given nick in "String user" is registered.
for(j=0; j<registered.length; j++) {
if(registered[j] != null) {
if(user.equals(registered[j])) {
//if it is then ask for password. The register[] and password[] arrays are sync. so register[0]'s password is in password[0].
reged = true;
out[clientnum].println("Password: ");
pass = in[clientnum].readLine();
if(pass.equals(password[j])) {
clientid[clientnum] = user;
out[clientnum].println("-------------------Welcome to ChatServer--------------------");
out[clientnum].println("Welcome back "+clientid[clientnum]+"!");
} else {
out[clientnum].println("Bad login");
out[clientnum].println("Registered Nick denined");
in[clientnum].close();
out[clientnum].close();
clients[clientnum].close();
return;
}
}
}
}
//if given nick is not registered then allow the client to have nick
if(!reged) {
clientid[clientnum] = user;
}
for(j=0; j<clients.length; j++) {
if(out[j] != null) {
out[j].println(clientid[clientnum]+" has joined us");
}
}
}
public void SendOut(int clientnum, String text) throws IOException {
//invoked in Listener.run();
//when client sends out a message, for through all the arrays and print the message out to all non-null clients
int j;
for(j=0; j<clients.length; j++) {
if(out[j] != null) {
out[j].println(clientid[clientnum]+": "+text);
}
}
}
public void Help(int clientnum) throws IOException {
//invoked in Listener.run():
//if user specifes /h command.
out[clientnum].println("/h help: display this help text.");
out[clientnum].println("/p <user> <message> private message: send a user private message.");
out[clientnum].println("/n <new_user_name> Change User name.");
out[clientnum].println("/r <password> Register this username.");
out[clientnum].println("/q quit: Leave Chat Server.");
}
public void Message(int clientnum, String user, String message) throws IOException {
//invoked in Listener.run();
//if user specifies /p <user> <message>.
int j;
boolean founduser = false;
for(j=0; j<clients.length; j++) {
//check to see if user exits
if(out[j] != null) {
if(clientid[j].equals(user)) {
//if user exist then send the message out to them
out[j].println("Private message from "+clientid[clientnum]+": "+message);
founduser = true;
break;
}
}
}
if(founduser) {
out[clientnum].println("Message send to "+user);
} else {
//else tell messenger that user doesn't exist
out[clientnum].println("User: "+user+" does not exist");
}
}
public void ChangeName(int clientnum, String newUser) {
//invoked in Listener.run();
//if user specifes /n <newick> command
int j;
boolean reged = false;
String olduser = clientid[clientnum];
//check to see if wanted nick is not registered
for(j=0; j<registered.length; j++) {
if(registered[j] != null) {
//if it is then deny command
if(newUser.equals(registered[j])) {
reged = true;
out[clientnum].println("Registered Nick, please logout and log back in to use");
}
}
}
if(!reged) {
//else change users nick and notify all clients
clientid[clientnum] = newUser;
for(j=0; j<clients.length; j++) {
if(out[j] != null) {
out[j].println(olduser+" is now known as "+clientid[clientnum]);
}
}
}
}
public void Register(int clientnum, String pass) throws IOException {
//invoked in Listener.run();
//if user specifes /r <password> command.
int j;
boolean exists = false;
//check to see if the nick is already registered.
for(j=0; j<registered.length; j++) {
if(registered[j] != null) {
if(registered[j].equals(clientid[clientnum])) {
out[clientnum].println("Nick is already registered");
exists = true;
}
}
}
if(!exists) {
//if it doesnt then write to file reg.txt the new username:password.
fileout.println(clientid[clientnum]+":"+pass);
out[clientnum].println("Nick has been registered");
}
}
public void Quit(int clientnum) throws IOException {
//invoked in Listener.run():
//if user specifies /q command.
//close clients socket and I/O handlers, and notify all clients that this user is leaving.
int j;
for(j=0; j<clients.length; j++) {
if(out[j] != null) {
out[j].println("Server: "+clientid[clientnum]+" has Quit");
}
}
in[clientnum].close();
out[clientnum].close();
clients[clientnum].close();
}
public static void main(String[] args) throws IOException {
ChatServer server = new ChatServer(7890);
server.Start();
}
}
//Clients input Thread
class Listener implements Runnable {
ChatServer self;
BufferedReader in;
PrintWriter out;
int clientnum;
String line;
public Listener(ChatServer cs, BufferedReader br, PrintWriter pw, int num) {
self = cs;
in = br;
out = pw;
clientnum = num;
}
public void run() {
//first off ask user for his/her nick, and pass that user and his/her clientnum to ChatServer.Welcome(int clientnum, String user);
try {
out.println("Give us a name: ");
line = in.readLine();
self.Welcome(clientnum, line);
while((line=in.readLine())!=null) {
//if client quits then pass his/her clientnum into ChatServer.Quit(int clientnum);
if(line.equals("/q")) {
self.Quit(clientnum);
//if client ask for help then pass clientnum off to ChatServer.Help(int clientnum);
} else if(line.equals("/h")) {
self.Help(clientnum);
//if client ask to message somebody, split the string only twice to get the user to message and the massage itself, then pass the clientnum, specifed user, and message string to ChatServer.Message(int clientnum, String user, String message);
} else if(line.startsWith("/p")) {
String lines[] = line.split(" ", 3);
self.Message(clientnum, lines[1], lines[2]);
//if client ask to change his/her nick, then split the string once and pass the clientnum and newnick to ChatServer.ChangeName(int clientnum, String newUser);
} else if(line.startsWith("/n")) {
String name[] = line.split(" ");
self.ChangeName(clientnum, name[1]);
//if client ask to register thier current nick, then split the string once and pass the clientnum and password to ChatServer.Register(int clientnum, String pass);
} else if(line.startsWith("/r")) {
String pass[] = line.split(" ");
self.Register(clientnum, pass[1]);
//if client doesnt specify command then pass the entire string to ChatServer.SendOut(int clientnum, String message);
} else {
self.SendOut(clientnum, line);
}
}
//Close client if readstream is broken.
self.Quit(clientnum);
} catch(IOException e) {}
}
}
p.s
No compiler errors/warnings nor runtime errors. Like i said the whole thing works tip top other than the problem mentioned.
need better IO management
Hello,
your problem is very simple to solve.
Simply you open a file for writing (new blank file) and you never invoke fileout.close() so you'll never see anything in the file.
I would suggest you to write some better code for IO. For not parallel programming (multithreading, client/server) you should be careful for locks on file. It's difficult to read and write a file at the same time without control.
first step for better code :
don't use a file reader opened only once but open the file for reading every time you need to read it. This is necessary because you write also to that file.
Code:
// the filein can remain static but it will be a new instance on every read
filein = new BufferedReader(new FileReader("reg.txt"));
// your reading
filein.readLine();
filein.close();
don't use a file writer opened only once but open the file for writing every time you need to write it. This is necessary because you want to read the updated file.
Code:
fileout = new PrintWriter(new FileWriter("reg.txt"));
// your writing - every time rewrites all
// if you want append search in documentation
fileout.println();
fileout.close();
the second step is to ensure mutual access to the file:
if you have more than one thread accessing in read or write your file you could have a runtime error or some incorrect content in the file. To ensure mutual access the easiest thing is to make the synchronized methods for reading and writing the file
Code:
private synchronized void readFile(){
// your reading
}
private synchronized void writeFile(){
// your writing
}
you see that the methods are synchonized which ensures that only one thread at the time can execute each of that methods
hope it helped