`

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

阅读更多
上一篇实现了简单的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();
		}
	}
}
分享到:
评论
11 楼 marshan 2009-08-25  
不要用ArrayList,它不是线程安全的,换成Vector。
10 楼 cjmcn-sh 2009-05-14  
大概就是这样的吧。可以试试。长连接服务器压力太大。
9 楼 cjmcn-sh 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);
8 楼 lucane 2009-05-13  
cjmcn-sh 写道
保存在list中还是可以的,楼主是选择长连接?保存以后还要做什么特殊处理?
会群发消息?

另外list需要做同步处理。

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


给在线所有用户发消息
7 楼 cjmcn-sh 2009-05-12  
保存在list中还是可以的,楼主是选择长连接?保存以后还要做什么特殊处理?
会群发消息?

另外list需要做同步处理。
6 楼 lucane 2009-05-12  
vinter 写道
lucane 写道

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

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

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

我也不是狠懂
正在找这方面的例子。。
5 楼 lqql 2009-05-12  
现在不都用NIO吗?
4 楼 vinter 2009-05-12  
lucane 写道

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

保存Socket要更好一些,比如要关掉某一个Socket连接,或者身某个Socket写信息,如果你要是保存Thread,然后Thread里面包含Socket的话,你想用什么方式实现?
3 楼 lucane 2009-05-11  
san_yun 写道
异常时候删除,list需要同步处理.

你说的是对的
但程序还是会出点bug
我这个代码list中放的是Thread
我有点觉得这样写是错的
我看到有别人是把Socket放在list中的
这样有区别吗
2 楼 san_yun 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需要同步处理.
1 楼 lucane 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();
			}
		}
	}
}

相关推荐

    java socket通信 一对多

    2)服务端程序能响应单个或任意多个客户端连接请求;服务端能向单个客户发送消息,支持群发消息给所有客户端; 3)通信的双方具备异常响应功能,包括对方异常退出的处理。如果客户端退出,服务器有响应;反之亦然。...

    socket编程,CS间相互通讯(含实验报告)

    2)服务端程序能响应单个或任意多个客户端连接请求;服务端能向单个客户发送消息,支持群发消息给所有客户端; 3)通信的双方具备异常响应功能,包括对方异常退出的处理。如果客户端退出,服务器有响应;反之亦然。 ...

    基于socket的聊天系统设计

    一个聊天系统的通信模块就是Socket程序的设计与实现,聊天系统分为服务器端和客户端,服务器端的任务就是接受客户端的不同请求,做出不同的响应,并处理多客户端之间的通信。 3.1头文件 /***********************...

    2024年java面试题-网络编程TCP、UDP、Socket、Http等面试题

    现在的网络编程基本上都是基于请求/响应方式的,也就是一个设备发送请求数据给另外一个,然后接收另一个设备的反馈。在网络编程中,发起连接程序,也就是发送第一次请求的程序,被称作客户端(Client),等待其他程序...

    C++项目-C++实现云盘项目实战-包括client端和server端

    该项目是在linux下采用C/C++编程,基于TCP协议,服务器端采用多进程长连接的socket的通信方式,并采用开源的负载均衡器G6作为客户端请求与服务端响应的中间件分发器。考虑到服务器端如果每接收到一个请求fork一个...

    HTTPclient-server:Java 中一个简单的 HTTP Server-Client 程序

    #描述这是一个用于 HTTP 客户端和服务器的简单 java Socket 程序HTTP 服务器... 此 HTTP 服务器是多线程的,因此它将同时处理多个客户端请求。 (尚未测试!但我相信如此。) ##内容HTTP服务器HTTP 客户端##参考

    代码客:G-Socket(IOCP) 1.0 (Server/Client)例程源码+Server体验程序+强大的压力测试工具

    (1)、工作线程:响应连接的IO投递返回并负责投递读请求,并将IO返回结果投递给处理线程,可设定参数决定工作线程数量; (2)、处理线程:处理线程调用回调函数将信息传递给应用层或协议栈,可设定参数决定工作处理...

    java源码包3

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    java网络编程技术课程设计.doc

    光用主机名或IP地址来标识这么多个进程显然是不够的,只有通过主机名或IP地址和端口 号的组合才能唯一的确定网络通讯中的对象:进程。服务类型是那些已经被TCP/IP协议 标准化的在TCP应用层上的应用,一般都是网络...

    C#聊天程序

    私聊与多聊、TCP运用 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Net.Sockets; using System...

    java源码包---java 源码 大量 实例

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    java源码包2

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    然后服务器处于等待状态 第二步:运行LoginData.java 启动(客户端)登陆界面 输入用户名 ip为本机localhost 第三步:在登陆后的界面文本框输入文本,然后发送 可以同时启动多个客户端 实现群聊。 浮动的广告 嵌套在...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    然后服务器处于等待状态 第二步:运行LoginData.java 启动(客户端)登陆界面 输入用户名 ip为本机localhost 第三步:在登陆后的界面文本框输入文本,然后发送 可以同时启动多个客户端 实现群聊。 浮动的广告 嵌套在...

    java源码包4

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    JAVA上百实例源码以及开源项目

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    JAVA上百实例源码以及开源项目源代码

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    HttpClient以及获取页面内容应用

    压缩包中含有多个文档,从了解httpclient到应用。 httpClient 1httpClint 1.1简介 HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持...

    travelibrary-微信小程序实战-流动图书馆.zip

    }获得微信用户的openId小程序前端会请求微信服务器得到一个code, 将code发送给自己的服务器,然后自己的服务器给微信服务器发送请求,得到微信用户的唯一标识openIdconst https = require('https'); const ...

Global site tag (gtag.js) - Google Analytics