论坛首页 Java企业应用论坛

服务器响应多个Client的Socket请求

浏览 20308 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (14) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-02-17  
上一篇实现了简单的Client/Server模型的Socket程序。但一般情况下Client会有多个,Server就需要响应多个Client的请求,下面的程序通过多线程实现了这个要求。
package test;

import java.io.*;
import java.net.*;

public class MultiServer {
	public MultiServer() throws IOException {
		ServerSocket ss=new ServerSocket(7777);
		while(true){
			Socket socket=ss.accept();
			new DealMessage(socket).start();
		}
	}
	public static void main(String[] args) {
		try {
			new MultiServer();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

class DealMessage extends Thread {
	private Socket socket;
	private InputStream in;
	private OutputStream out;

	public DealMessage(Socket s) throws IOException {
		this.socket = s;
		this.in = socket.getInputStream();
		this.out = socket.getOutputStream();
	}

	public void run() {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			System.out.println("you IP is: " + socket.getInetAddress()+":"+socket.getPort());
			System.out.println("you enter is: " + br.readLine());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void finalize() throws IOException {
		if (in != null) {
			in.close();
		}
		if (out != null) {
			out.close();
		}
	}
}
   发表时间:2009-05-11  
我在服务器端维护了一个客户端请求的list
当客户端退出时,服务器端将这个请求的客户端删除
在这里遇到了些问题
主要不知道怎么讲list中下线的客户端删除
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ChatServer {

	List<Client> clients = new ArrayList<Client>();

	public static void main(String[] args) {
		new ChatServer().start();
	}

	public void start() {
		boolean started = false;
		ServerSocket ss = null;
		try {
			ss = new ServerSocket(8888);
			started = true;
		} catch (BindException e) {
			System.out.println("端口正在被使用,请关闭相应程序!");
			System.exit(0);
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			while (started) {
				Socket s = ss.accept();
				Client c = new Client(s);
				clients.add(c);
				System.out.println("a client connected!");
				new Thread(c).start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 每个请求过来启用一个线程来处理<br>
	 */
	private class Client implements Runnable {
		Socket socket = null;
		DataInputStream dis = null;
		DataOutputStream dos = null;
		boolean connected = false;

		Client(Socket s) {
			try {
				this.socket = s;
				dis = new DataInputStream(s.getInputStream());
				dos = new DataOutputStream(s.getOutputStream());
				connected = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		public void run() {
			while (connected) {
				try {
					Iterator<Client> it = clients.iterator();
					String msg = dis.readUTF();
					while (it.hasNext()) {
						Client c = it.next();
						c.send(msg);
					}

				} catch (EOFException eof) {
					connected = false;
					// 需要在序列中将退出的client去除,
					// 迭代过程中
					// 不能使用Collection本身的remove方法,
					// 会抛出java.util.ConcurrentModificationException
					// 使用iterator的remove方法
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		private void send(String str) throws IOException {
			dos.writeUTF(str);
		}
	}
}


public class ChatClient extends Frame {
	private static final long serialVersionUID = 5798410085795768914L;
	public TextField tf = new TextField();
	public TextArea ta = new TextArea();

	DataOutputStream dos = null;
	DataInputStream dis = null;

	public Socket socket = null;

	boolean connected = false;

	Thread receiver = new Thread(new ReceiverThread());

	public static void main(String[] args) {
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		this.setLocation(250, 100);
		this.setSize(500, 600);
		this.add(tf, BorderLayout.SOUTH);
		this.add(ta, BorderLayout.NORTH);
		this.pack();
		this.addWindowListener(new WindowMonitor());
		tf.addKeyListener(new KeyMonitor());
		connect();
		receiver.start();
		this.setVisible(true);
	}

	public void connect() {
		try {
			socket = new Socket("127.0.0.1", 8888);
			dos = new DataOutputStream(socket.getOutputStream());
			dis = new DataInputStream(socket.getInputStream());
			connected = true;
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void disconnect() {
		try {
			dos.close();
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private class WindowMonitor extends WindowAdapter {
		@Override
		public void windowClosing(WindowEvent e) {
			disconnect();
			System.exit(0);
		}
	}

	private class KeyMonitor extends KeyAdapter {
		@Override
		public void keyPressed(KeyEvent e) {
			int keyCode = e.getKeyCode();
			if (KeyEvent.VK_ENTER == keyCode) {
				try {
					dos.writeUTF(tf.getText().trim());
					dos.flush();
				} catch (IOException ioe) {
					ioe.printStackTrace();
				}
				tf.setText("");
			}
		}
	}

	private class ReceiverThread implements Runnable {

		public void run() {
			try {
				while (connected) {
					String str = dis.readUTF();
					ta.setText(ta.getText() + str + '\n');
				}
			} catch (SocketException e) {
				System.out.println("客户端断开连接!");
				connected = false;
			} catch (EOFException e) {
				System.out.println("客户端断开连接!");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
0 请登录后投票
   发表时间:2009-05-11  
lucane 写道
我在服务器端维护了一个客户端请求的list
当客户端退出时,服务器端将这个请求的客户端删除
在这里遇到了些问题
主要不知道怎么讲list中下线的客户端删除
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ChatServer {

	List<Client> clients = new ArrayList<Client>();

	public static void main(String[] args) {
		new ChatServer().start();
	}

	public void start() {
		boolean started = false;
		ServerSocket ss = null;
		try {
			ss = new ServerSocket(8888);
			started = true;
		} catch (BindException e) {
			System.out.println("端口正在被使用,请关闭相应程序!");
			System.exit(0);
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			while (started) {
				Socket s = ss.accept();
				Client c = new Client(s);
				clients.add(c);
				System.out.println("a client connected!");
				new Thread(c).start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 每个请求过来启用一个线程来处理<br>
	 */
	private class Client implements Runnable {
		Socket socket = null;
		DataInputStream dis = null;
		DataOutputStream dos = null;
		boolean connected = false;

		Client(Socket s) {
			try {
				this.socket = s;
				dis = new DataInputStream(s.getInputStream());
				dos = new DataOutputStream(s.getOutputStream());
				connected = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		public void run() {
			while (connected) {
				try {
					Iterator<Client> it = clients.iterator();
					String msg = dis.readUTF();
					while (it.hasNext()) {
						Client c = it.next();
						c.send(msg);
					}

				} catch (EOFException eof) {
					connected = false;
					// 需要在序列中将退出的client去除,
					// 迭代过程中
					// 不能使用Collection本身的remove方法,
					// 会抛出java.util.ConcurrentModificationException
					// 使用iterator的remove方法
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		private void send(String str) throws IOException {
			dos.writeUTF(str);
		}
	}
}


public class ChatClient extends Frame {
	private static final long serialVersionUID = 5798410085795768914L;
	public TextField tf = new TextField();
	public TextArea ta = new TextArea();

	DataOutputStream dos = null;
	DataInputStream dis = null;

	public Socket socket = null;

	boolean connected = false;

	Thread receiver = new Thread(new ReceiverThread());

	public static void main(String[] args) {
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		this.setLocation(250, 100);
		this.setSize(500, 600);
		this.add(tf, BorderLayout.SOUTH);
		this.add(ta, BorderLayout.NORTH);
		this.pack();
		this.addWindowListener(new WindowMonitor());
		tf.addKeyListener(new KeyMonitor());
		connect();
		receiver.start();
		this.setVisible(true);
	}

	public void connect() {
		try {
			socket = new Socket("127.0.0.1", 8888);
			dos = new DataOutputStream(socket.getOutputStream());
			dis = new DataInputStream(socket.getInputStream());
			connected = true;
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void disconnect() {
		try {
			dos.close();
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private class WindowMonitor extends WindowAdapter {
		@Override
		public void windowClosing(WindowEvent e) {
			disconnect();
			System.exit(0);
		}
	}

	private class KeyMonitor extends KeyAdapter {
		@Override
		public void keyPressed(KeyEvent e) {
			int keyCode = e.getKeyCode();
			if (KeyEvent.VK_ENTER == keyCode) {
				try {
					dos.writeUTF(tf.getText().trim());
					dos.flush();
				} catch (IOException ioe) {
					ioe.printStackTrace();
				}
				tf.setText("");
			}
		}
	}

	private class ReceiverThread implements Runnable {

		public void run() {
			try {
				while (connected) {
					String str = dis.readUTF();
					ta.setText(ta.getText() + str + '\n');
				}
			} catch (SocketException e) {
				System.out.println("客户端断开连接!");
				connected = false;
			} catch (EOFException e) {
				System.out.println("客户端断开连接!");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

异常时候删除,list需要同步处理.
0 请登录后投票
   发表时间:2009-05-11   最后修改:2009-05-11
san_yun 写道
异常时候删除,list需要同步处理.

你说的是对的
但程序还是会出点bug
我这个代码list中放的是Thread
我有点觉得这样写是错的
我看到有别人是把Socket放在list中的
这样有区别吗
0 请登录后投票
   发表时间:2009-05-12  
lucane 写道

san_yun 写道异常时候删除,list需要同步处理.
你说的是对的
但程序还是会出点bug
我这个代码list中放的是Thread
我有点觉得这样写是错的
我看到有别人是把Socket放在list中的
这样有区别吗

保存Socket要更好一些,比如要关掉某一个Socket连接,或者身某个Socket写信息,如果你要是保存Thread,然后Thread里面包含Socket的话,你想用什么方式实现?
0 请登录后投票
   发表时间:2009-05-12  
现在不都用NIO吗?
0 请登录后投票
   发表时间:2009-05-12  
vinter 写道
lucane 写道

san_yun 写道异常时候删除,list需要同步处理.
你说的是对的
但程序还是会出点bug
我这个代码list中放的是Thread
我有点觉得这样写是错的
我看到有别人是把Socket放在list中的
这样有区别吗

保存Socket要更好一些,比如要关掉某一个Socket连接,或者身某个Socket写信息,如果你要是保存Thread,然后Thread里面包含Socket的话,你想用什么方式实现?

我开始想的是从list中删除的话
socket这些资源应该会被回收

我也不是狠懂
正在找这方面的例子。。
0 请登录后投票
   发表时间:2009-05-12  
保存在list中还是可以的,楼主是选择长连接?保存以后还要做什么特殊处理?
会群发消息?

另外list需要做同步处理。
0 请登录后投票
   发表时间:2009-05-13  
cjmcn-sh 写道
保存在list中还是可以的,楼主是选择长连接?保存以后还要做什么特殊处理?
会群发消息?

另外list需要做同步处理。

应该算是长连接
想让用户退出的时候断开链接


给在线所有用户发消息
0 请登录后投票
   发表时间:2009-05-14  
搞点代码示意一下:
private static final Set UserSet= Collections
            .synchronizedSet(new HashSet());
然后分几种状态:
OnAccept:
  UserSet.add(Socket);
OnClose;
  UserSet.remove(Socket);
OnSend:
  synchronized (UserSet){
  按照UserSet中socket发送
}
OnException:
UserSet.remove(Socket);
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics