Multithreaded Client-Server socket programming in Java - java

I'm having an issue with a messaging app I'm working on and was hoping someone could point me in the right direction. I'm stuck on getting the client and server to communicate properly.
My client multicasts a message to 5 processes, which make their alterations on the server side and send them back to the client. This all works fine, however when I try to multicast a second time, the server is getting stuck reading and eventually gives me the error: W/System.err (with no other information) at the line I point out in the code.
Client code:
private class ClientTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... msgs) {
try{
String msg = msgs[0];
int ID = Integer.parseInt(msgs[1]);
ObjectOutputStream out;
clock++;
Message m1 = new Message(clock, msg, ID);
for (int i = 0; i < 5; ++i) {
String remotePort = REMOTE_PORT[i];
Socket socket = new Socket(InetAddress.getByAddress(new byte[]{10, 0, 2, 2}),
Integer.parseInt(remotePort));
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(m1);
out.flush();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Message m2 = (Message)in.readObject();
proposed_seq_from_q = m2.seq_number;
all_proposed.add(proposed_seq_from_q);
socket.close();
}
agreed_deliver = Collections.max(all_proposed);
m1.set_seq_number(agreed_deliver);
for (int i = 0; i < 5; ++i) {
String remotePort = REMOTE_PORT[i];
Socket socket = new Socket(InetAddress.getByAddress(new byte[]{10, 0, 2, 2}),
Integer.parseInt(remotePort));
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(m1);
out.flush();
socket.close();
}
} catch(ClassNotFoundException e){
Log.e(TAG, "ClientTask: ClassNotFoundException");
e.printStackTrace();
} catch (UnknownHostException e) {
Log.e(TAG, "ClientTask: UnknownHostException");
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG, "ClientTask: IOException");
e.printStackTrace();
}
return null;
}
}
Server code:
private class ServerTask extends AsyncTask<ServerSocket, String, Void> {
#Override
protected Void doInBackground(ServerSocket... sockets) {
ServerSocket serverSocket = sockets[0];
boolean listening = true;
try{
while(listening) {
Socket clientSocket = serverSocket.accept();
ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
Message m = (Message)in.readObject();
new_proposed = Math.max(new_proposed + 1, clock);
m.set_seq_number(new_proposed);
ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream());
out.writeObject(m);
holdback_queue.add(m);
// ******************************************************
// THIS IS WHERE IT IS CRASHING
// ******************************************************
m = (Message)in.readObject();
publishProgress(m.get_message());
}
}catch(Exception e){
Log.e(TAG, "FAIL");
e.printStackTrace();
}
return null;
}
I've tried everything I can think of but I'm unable to get the server to read the second message. Everything is working up and being passed through with no issues up until that exact point. Can anyone please tell me what I'm doing wrong?

Related

Connection with sockets between Java and C#

when I try to send or receive a message with the sockets I can not do it, in java it tells me that the conecction was denied while in c# it tells me that the port is already being used, in java I send my message by clicking a button and I receive it with a thread and in a similar way in c#, I would really appreciate if you could tell me what is wrong, I have tried everything but I can not find the answer, thanks.
Java
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String mensaje = jTextField1.getText();
System.out.println(mensaje);
byte men[] = mensaje.getBytes();
Socket socket = null;
ObjectOutputStream out = null;
try {
socket = new Socket("127.0.0.1", 7000);
out = new ObjectOutputStream(socket.getOutputStream());
out.write(men, 0, men.length);
out.close();
socket.close();;
} catch (Exception e) {
e.printStackTrace();
}
}
class HiloReceptor extends Thread {
#Override
public void run() {
super.run();
while (true) {
try {
ServerSocket ss = new ServerSocket(7000);
Socket socketCanal = ss.accept();
ObjectInputStream ois = new ObjectInputStream(socketCanal.getInputStream());
byte[] mensaje = new byte[1024];
ois.read(mensaje, 0, mensaje.length);
String msgRecibido = new String(mensaje, 0 ,mensaje.length);
System.out.println(msgRecibido);
jLabel1.setText("Mensaje recibido: " + msgRecibido);
ois.close();
socketCanal.close();
ss.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
C#
private void button1_Click(object sender, EventArgs e)
{
try
{
String mensaje = textBox1.Text;
Console.WriteLine(mensaje);
byte[] men = UTF8Encoding.UTF8.GetBytes(mensaje);
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint endp = new IPEndPoint(ip, 7000);
TcpListener tcpListener = new TcpListener(endp);
tcpListener.Start();
//Socket socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Socket socket = tcpListener.AcceptSocket();
//socket.Connect(endp);
socket.Send(men, men.Length, 0);
socket.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error al enviar.\n" + ex);
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!backgroundWorker1.CancellationPending)
{
try
{
Console.WriteLine("entre al ciclo");
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint endp = new IPEndPoint(ip, 7000);
Socket s = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
s.Bind(endp);
s.Listen(1);
Socket canal = s.Accept();
byte[] buffer = new byte[1024];
msg = "";
while (canal.Receive(buffer, buffer.Length, 0) > 0)
{
msg += Encoding.UTF8.GetString(buffer);
}
Console.WriteLine(msg);
backgroundWorker1.ReportProgress(1);
canal.Close();
s.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error.\n"+ ex);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 1)
{
label1.Text = "Mensaje recibido: " + msg;
}
}

Socket's input stream still gets data after I closed the other side socket

Socket's methods do not appear to function in the way their names or documentation suggest. For example. I create a client socket to connect a remote serversocket. When the connection establishes, the serversocket.accept() method returns a corresponding socket which to getinputstream from the client socket. But the problem is, if I close the client socket, the socket on the server still returns false for the isClosed() method; and, more absurdly, the Socket's InputStream on the server starts to continuously return value and no longer blocks when the client socket has closed and sending no output to the server. Below is my code:
Client code:
public class MainActivity extends AppCompatActivity {
private Button startButton, stopButton;
public byte[] buffer;
public Socket socket;
public Socket tempSocket;
private int port = 50005;
InetSocketAddress address;
private int r_port = 50006;
AudioRecord recorder;
AudioTrack audioTrack;
private int sampleRate = 16000; // 44100 for music
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
public static boolean s_status = true;
public static boolean r_status = true;
Thread r_Thread;
Thread s_Thread;
private boolean isPlay = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button) findViewById(R.id.start_button);
startButton.setOnTouchListener(talkListener);
if (socket == null) {
socket = new Socket();
address = new InetSocketAddress("192.168.0.2", port);
try {
socket.setReuseAddress(true);
System.out.println("connecting-");
} catch (IOException e) {
e.printStackTrace();
}
}
}
private final View.OnTouchListener talkListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startButton.setBackgroundColor(Color.parseColor("#0670c0"));
try {
startStreamings();
} catch (Exception e) {
e.printStackTrace();
}
return true; // if you want to handle the touch event
case MotionEvent.ACTION_UP:
startButton.setBackgroundColor(Color.parseColor("#353535"));
try {
s_status = false;
} catch (Exception e) {
e.printStackTrace();
return true; // if you want to handle the touch event
}
}
return false;
}
};
public void startStreamings(){
s_status=true;
buffer = new byte[minBufSize];
s_Thread = new Thread(new Runnable() {
#Override
public void run() {
if (socket == null) {
try {
socket = new Socket();
socket.setReuseAddress(true);
} catch (IOException e) {
e.printStackTrace();
}
}
if (!socket.isConnected()) {
try {
socket.connect(address);
System.out.println("create new connection in startStreaming");
} catch (IOException e) {
e.printStackTrace();
}
}
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, minBufSize * 10);
try {
if (s_status == true) {
recorder.startRecording();
}
} catch (IllegalStateException e) {
e.printStackTrace();
return;
}
OutputStream os = null;
while (s_status == true) {
//reading data from MIC into buffer
recorder.read(buffer, 0, buffer.length);
try {
os = socket.getOutputStream();
os.write(buffer, 0, minBufSize);
} catch (Exception e) {
e.printStackTrace();
s_status = false;
}
//System.out.println("streaming out: " + buffer.length + "fff" + c++);
}
if (recorder != null) {
recorder.stop();
recorder.release();
recorder = null;
}
}
});
s_Thread.start();
}
}
Server code:
public TcpServerSocket(){
}
public static void main(String args[]) throws Exception {
ServerSocket serverSocket = new ServerSocket(port);
sockets = new ArrayList<Socket>();
while(isListenning){
Socket socket = serverSocket.accept();
isMatched = false;
for(int i =0;i<sockets.size();i++){
Socket preSocket = sockets.get(i);
if(preSocket.getInetAddress().equals(socket.getInetAddress())){
sockets.remove(preSocket);
sockets.add(socket);
isMatched = true;
}
}
if(!isMatched){
sockets.add(socket);
socket.setKeepAlive(false);
new Thread(new TcpServerSocket(socket)).start();
System.out.println("new Connection");
}
}
serverSocket.close();
}
#Override
public void run() {
byte[] receiveData = new byte[1280];
byte[] emptyData = new byte[1280];
InputStream baiss = null;
OutputStream os;
while (isRunning){
try {
baiss = csocket.getInputStream();
if(csocket.isClosed()||!csocket.isConnected()){
isRunning = false;
sockets.remove(csocket);
System.out.println("socket closed!");
}
int numOfBytes = baiss.read(receiveData);
if(numOfBytes==-1){
isRunning=false;
sockets.remove(csocket);
csocket.close();
System.out.println("socket closed!");
}
} catch (IOException e) {
sockets.remove(csocket);
System.out.println("socket closed!");
e.printStackTrace();
}
int socketsLen = sockets.size();
for(int i = 0;i<socketsLen;i++){
Socket client = sockets.get(i);
if(!client.getInetAddress().equals(csocket.getInetAddress())){
try {
os = client.getOutputStream();
os.write(receiveData,0,1280);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(!client.equals(csocket)){
csocket = client;
System.out.println("switched!");
}
}
System.out.println(csocket.getInetAddress().toString()+"fff"+socketsLen);
}
try {
baiss.close();
csocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Can you guys give me any suggestions to close the client socket perfectly so I won't keep getting input after I close the client? Any help is much appreciated!
socket.getInputStream() still get data after I closed the other side socket
That could be because there was still data in transit that hadn't been read yet. Closing a connection doesn't abort pending data transfers. But as it turns out, it doesn't get data at all. There is simply a bug in your code.
I am really upset with socket in recent days.
I suggest you get over being upset and adopt a rational attitude towards your chosen profession.
I find socket's methods just do not function in the way their names or documentations suggest.
Let's see.
For example. I create a client socket to connect a remote serversocket. When the connection establishes,the serversocket.accept() method returns a corresponding socket which to getinputstream from the client socket. But the problem is, if I close the client socket, the socket on the server still returns true for the isClosed() method
No it doesn't. It returns false. The server's socket is still open. The client's socket is closed, and so is the connection, but isClosed() tells you about the state of the socket it is called on, not anything else, and specifically not the connection.
and more absurd, the socket.getInputStream() on the server starts to continuously return value and no longer blocks when the client socket has closed and sending no outputstream to the server.
Only if there was data in flight before the peer closed. Otherwise it is due to a bug in your code, and here it is:
//reading data from MIC into buffer
recorder.read(buffer, 0, buffer.length);
read() returns -1 at end of stream, and you are ignoring it. That's why you get a continous loop. The correct way to write this code is as follows:
int count = recorder.read(buffer, 0, buffer.length);
if (count == -1) {
recorder.close();
socket.close();
break;
}
try {
os = socket.getOutputStream();
os.write(buffer, 0, count);
You have a similar problem with your client code. You just don't seem to care about end of stream:
baiss = csocket.getInputStream();
if(csocket.isClosed()||!csocket.isConnected()){
isRunning = false;
sockets.remove(csocket);
System.out.println("socket closed!");
}
baiss.read(receiveData);
// ...
os = client.getOutputStream();
os.write(receiveData,0,1280);
The correct way to write this is as follows:
baiss = csocket.getInputStream();
int count = baiss.read(receiveData);
if(count == -1){
isRunning = false;
sockets.remove(csocket);
System.out.println("socket closed!");
}
// ...
os = client.getOutputStream();
os.write(receiveData, 0, count);
Can you guys give me any suggestions to close the client socket perfectly so I won't keep getting input after I close the client?
You are closing it perfectly. The problem is that you aren't detecting it correctly at the other end.

server thread show connection problems

I created a server thread(using sockets). I recently got a new requirement that I need to add message to the user to notify him when there is a problem with the communication, I added a counter that counts how many exception I have during the communication lose and if it's equal to SERVER_MAX_NUM_TRIES I need to show to the user the message.
I tried many things but it does not work as it is suppose to.
This is my code so far:
public ServerNetworkThread()
{
setName("ServerNetworkThread");
_port = 5555;
_excetionCounter = 0;
}
#Override
public void run()
{
_isWorking = true;
while(_isWorking)
{
try
{
_serverSocket = new ServerSocket();
_serverSocket.setReuseAddress(true);
_serverSocket.bind(new InetSocketAddress(_port));
_socket = _serverSocket.accept();
_socket.setSoTimeout(Consts.CLIENT_SOCKET_TIMEOUT);
parseCommand();
_socket.close();
_serverSocket.close();
_excetionCounter = 0;
}
catch (IOException e)
{
Log.d("anton","server got exception _excetionCounter="+_excetionCounter);
e.printStackTrace();
_excetionCounter++;
if(_excetionCounter == SERVER_MAX_NUM_TRIES)
{
_isWorking = false;
Logics.getInstance().getNetworkManager().sendCommand(_handler, Consts.Requests.CONNECTION_SERVER_ERROR_MESSAGE, null);
}
}
}
}
private void parseCommand() throws IOException
{
InputStream iStream = _socket.getInputStream();
InputStreamReader in = new InputStreamReader(iStream, Charset.forName("UTF-16LE"));
DataOutputStream outToClient = new DataOutputStream(_socket.getOutputStream());
char[] buf = new char[1024];
int lettersCount = in.read(buf, 0, buf.length);
String request = new String(buf,0,lettersCount);
String responseStr = parseResponse(request);
byte[] response = responseStr.getBytes("UTF-16LE");
outToClient.write(response);
outToClient.flush();
outToClient.close();
in.close();
}
}
When I simulate a communication problem unplug the Ethernet cable nothing is happening.
UPDATE:
without using the second inner loop I'm getting this exception
java.net.BindException: bind failed: EADDRINUSE (Address already in use)

Android TCP multicast missing message

I build a TCP multicast chat application using asynctask.
I am also trying to order the message in FIFO and causal order.
However, when I try to send a lot of messages simultaneously for testing, it misses some messages but I can't find the reason.
I have tried as hard as I can to improve the performance of the program because I thought the performance could be the reason. but still having the same issue.
I attached some important part of my code.
Most of all,
private class ServerTask extends AsyncTask<ServerSocket, String, Void> {
#Override
protected Void doInBackground(ServerSocket... sockets){
ServerSocket serverSocket = sockets[0];
Socket socket = new Socket();
try {
while(true) {
socket = serverSocket.accept();
InputStream inputstream = socket.getInputStream();
DataInputStream in = new DataInputStream(new BufferedInputStream(inputstream));
String msg = ""+in.readUTF();
String time = ""+in.readUTF();
String temp = time+"||"+msg;
publishProgress(temp);
in.close();
}} catch (IOException e) {
e.printStackTrace();
} finally{
try {
socket.close();
serverSocket.close();////
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
Here is onProgressUpdate.
protected void onProgressUpdate(String...strings) {
/*
* The following code displays what is received in doInBackground().
*/
String strReceived = strings[0].trim();
TextView remoteTextView = (TextView) findViewById(R.id.textView1);
remoteTextView.append(strReceived + "\t\n");
try {
sequencer(strReceived);
} catch (ParseException e) {
e.printStackTrace();
}
return;
}
}
..
private class ClientTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... msgs) {
Date currentDate= new Date();
Timestamp time = new Timestamp(currentDate.getTime());
Message temp = new Message(myPort, msgs[0], time);////
try {
for(int i = 0; i <= 2; i++) {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(InetAddress.getByAddress(new byte[]{10, 0, 2, 2}),
Integer.parseInt(REMOTE_PORTS[i])), 1000);
socket.setTcpNoDelay(true);
OutputStream outputStream = socket.getOutputStream();
DataOutputStream o = new DataOutputStream(new BufferedOutputStream(outputStream));
o.writeUTF(msgs[0]);
o.writeUTF(""+time);
o.flush();////
socket.close();
}
}
catch (UnknownHostException e) {
Log.e(TAG, "ClientTask UnknownHostException");
} catch (IOException e) {
Log.e(TAG, "ClientTask socket IOException");
}
return null;
}
Can you find the part causes the problem?
Sequencing / Queueing /Acknowledgement all these things are part of TCP so it is done by the protocol itself so you do not need to do all those explicitly from your code. There are still some parts of your code that can be improved. Like:
String time = received.split("\\|\\|")[0];
String msgToSend = received.split("\\|\\|")[1];
//Instead of doing this, its better to do this:
String peices[]=received.split("\\|\\|");
String msgToSend=peices[1];
String time=peices[0]
Also you can check if you are receiving all the raw messages and if its during the parsing process the messages are getting lost using a log:
Log.d("RAW_MESSAGE","Message Received: "+temp); //in your doInBackground
If you get all the messages that you send in this log, then there is nothing wrong with the protocol or the sending/receiving process rather there is a problem while you are processing the message. Also for these types of use-cases, try using the Service component rather than AsyncTask.
I hope this helps.
First of all multicast is over UDP, not TCP.
And if you want to create a multicast app, you should use multicastsocket
http://developer.android.com/reference/java/net/MulticastSocket.html

Server Send Out message from one client to all Clients conneted. JAVA

I am writing a Server/Client chat where basically Multiple Clients connected to One Server. One client send a message to server Then all other Clients will get the same message. For example: Client A, B, C Connected to A same Server. Client A send Message To Server, Server then will send the same message to client B and C but exclude Client A.
I'm stuck at part where Server send out the message to all other clients.
Below is the code, I'm just a Java beginner so any help with the code will be much appreciate.
ServerSide
public class ServerP2P extends Thread{
private ServerSocket server = null;
private Socket clientSocket = null;
private ArrayList<ServerThread> clientThreadList = new ArrayList<>();
private int maxClient = 4;
private int port = 9990;
boolean listening = true;
public ServerP2P(){
try{
server = new ServerSocket(port);
}catch(IOException e){
e.printStackTrace();
return;
}
System.out.println("Server with Port "+port+" is Up and Running");
}
public void run(){
System.out.println("Room Chat Is Up");
while(listening){
for(int i = 0;i<clientThreadList.size();i++){
if(!clientThreadList.get(i).getConneection()){
System.out.println(clientThreadList.get(i)+" is removing from server because there is no conntection");
clientThreadList.remove(i);
}
}
try{
clientSocket = server.accept();
}catch(Exception e){
e.printStackTrace();
}
System.out.println("User with IP "+clientSocket.getInetAddress()+" Has Connected to Server");
clientThreadList.add(new ServerThread(clientSocket));
try{
Thread.sleep(200);
}catch(Exception e){
e.printStackTrace();
}
}
}
public ArrayList<ServerThread> listOFClient(){
return clientThreadList;
}
public static void main(String[] args){
ServerP2P server = new ServerP2P();
server.start();
}
}
ServerThread
public class ServerThread{
private Socket clientSocket;
private boolean connected;
private Incomming incommingData;
String msg = null;
private class Incomming extends Thread{
private DataInputStream input;
public void run(){
try{
input = new DataInputStream(clientSocket.getInputStream());
}catch(IOException e){
e.printStackTrace();
return;
}
System.out.println("User with IP "+clientSocket.getInetAddress()+" has connected");
while(true){
try{
Thread.sleep(200);
int msgSize = input.readInt();
byte[] msgByte = new byte[msgSize];
for(int i = 0; i < msgSize ; i++){
msgByte[i] = input.readByte();
}
msg = new String(msgByte);
System.out.println(msg);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
public ServerThread(Socket newClientSocket){
this.clientSocket = newClientSocket;
connected = true;
incommingData = new Incomming();
incommingData.start();
}
public boolean getConneection(){
return connected;
}
public void closeConnection(){
try{
connected = false;
clientSocket.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
ClientSide
public class ClientP2P{
private Socket serverSocket = null;;
private DataOutputStream output = null;
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
public static void main(String[] args) {
ClientP2P client = new ClientP2P();
client.startConnect();;
}
public void startConnect(){
int port = 9990;
try {
serverSocket = new Socket("localhost", port);
System.out.println(serverSocket.isBound());
output = new DataOutputStream(serverSocket.getOutputStream());
System.out.println("Please Enter Your name: ");
String nameClient = reader.readLine();
output.writeInt(nameClient.length());
output.writeBytes(nameClient);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("You Are Connected");
System.out.println("Chat Can Start");
sendText();
}
public void sendText(){
try {
while (true) {
System.out.println("Type Message: ");
String msg = reader.readLine();
output.writeInt(msg.length());
output.writeBytes(msg);
System.out.println("Message sent");
recivedText();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void recivedText(){
try{
DataInputStream input = new DataInputStream(serverSocket.getInputStream());
int textSize = 0;
while(input.available() != 0){
byte[] byteString = new byte[textSize];
for(int i = 0; i < textSize;i++){
byteString[i] = input.readByte();
}
String txtServer = new String(byteString);
System.out.println(txtServer);
textSize = 0;
}
sendText();
}catch(Exception e){
e.printStackTrace();
}
}
}
Thanks For Your Time Guys.
Your ServerThread receives the messages and you want to send them to all other clients. One way you could achieve is to have the clients register themselves with the Server (this would help in the server not knowing the clients when it starts, which ideally should be the case). In your ServerThread, get a list of available clients from the server and loop through them and send the message to each one of them.
Use ObserverDesign pattern to hold the list of all your buddy/user to whom you wish to send message. Use HashMap to maintain a list of all the observer and its socket. Once the message is received, you retrieve the sockets of each user and write the same message on each socket.

Categories

Resources