Java 向多个客户发布过帐
嘿,伙计们,我最近刚开始使用套接字,但在向多个客户发布时遇到了一个问题。我使用多线程来处理这个问题,我试图在hashmap中保存服务器需要发送的所有客户端数据,但是在循环并添加到hashmap时。它似乎只增加了一个人。这是密码Java 向多个客户发布过帐,java,sockets,hashmap,Java,Sockets,Hashmap,嘿,伙计们,我最近刚开始使用套接字,但在向多个客户发布时遇到了一个问题。我使用多线程来处理这个问题,我试图在hashmap中保存服务器需要发送的所有客户端数据,但是在循环并添加到hashmap时。它似乎只增加了一个人。这是密码 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import ja
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
public class HostMain extends Thread {
/**
* The set of all names of clients in the chat room. Maintained
* so that we can check that new clients are not registering name
* already in use.
*/
private static HashMap<String, ConnectedUsers> users = new HashMap<String, ConnectedUsers>();
public HostMain() throws IOException
{
}
public void run()
{
try
{
System.err.println("SERVER:The chat server is running.");
ServerSocket listener = new ServerSocket(PORT);
System.err.println("SERVER:socket created");
Constants.getInstance().getStatusLabel().setText("Server is running. Join when ready");
try {
while (true) {
System.err.println("SERVER:New handler being created");
new Handler(listener.accept()).start();
}
} finally {
listener.close();
}
}
catch(Exception e)
{
Constants.getInstance().getStatusLabel().setText("SERVER:A HOST IS ALREADY RUNNING ON THIS PORT!");
System.err.println("SERVER:A HOST IS ALREADY RUNNING ON THIS PORT!");
}
}
/**
* The port that the server listens on.
*/
private static final int PORT = 1337;
/**
* The appplication main method, which just listens on a port and
* spawns handler threads.
*/
/**
* A handler thread class. Handlers are spawned from the listening
* loop and are responsible for a dealing with a single client
* and broadcasting its messages.
*/
private static class Handler extends Thread {
private String name;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private ObjectInputStream oin;
private ObjectOutputStream oout;
/**
* Constructs a handler thread, squirreling away the socket.
* All the interesting work is done in the run method.
*/
public Handler(Socket socket) {
this.socket = socket;
}
/**
* Services this thread's client by repeatedly requesting a
* screen name until a unique one has been submitted, then
* acknowledges the name and registers the output stream for
* the client in a global set, then repeatedly gets inputs and
* broadcasts them.
*/
public void run() {
try {
// Create object streams for the socket.
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
oin = new ObjectInputStream(socket.getInputStream());
oout = new ObjectOutputStream(socket.getOutputStream());
//add socket to a list
users.put(name,new ConnectedUsers(name,oout));
System.err.println(users.size());
// Accept messages from this client and broadcast them.
// Ignore other clients that cannot be broadcasted to.
while (true) {
Object obj = oin.readObject();
Messages message = (Messages)obj;
if(obj.getClass().equals(Messages.class))
{
for(Map.Entry<String, ConnectedUsers> entry:users.entrySet())
{
ConnectedUsers user = entry.getValue();
user.objectWriter.writeObject(message);
}
}
}
} catch (IOException | ClassNotFoundException e) {
System.out.println(e);
} finally {
// This client is going down! Remove its name and its print
// writer from the sets, and close its socket.
if (name != null) {
users.remove(name);
}
try {
socket.close();
} catch (IOException e) {
}
}
}
}
}
导入java.io.BufferedReader;
导入java.io.IOException;
导入java.io.InputStreamReader;
导入java.io.ObjectInputStream;
导入java.io.ObjectOutputStream;
导入java.io.PrintWriter;
导入java.net.ServerSocket;
导入java.net.Socket;
导入java.util.HashMap;
导入java.util.HashSet;
导入java.util.Iterator;
导入java.util.Map;
公共类HostMain扩展线程{
/**
*聊天室中所有客户端名称的集合。已维护
*这样我们就可以检查新客户端是否未注册名称
*已经在使用中。
*/
private static HashMap users=new HashMap();
public HostMain()引发IOException
{
}
公开募捐
{
尝试
{
System.err.println(“服务器:聊天服务器正在运行。”);
ServerSocket侦听器=新的ServerSocket(端口);
System.err.println(“服务器:已创建套接字”);
常量.getInstance().getStatusLabel().setText(“服务器正在运行,准备好后加入”);
试一试{
while(true){
System.err.println(“服务器:正在创建新的处理程序”);
新处理程序(listener.accept()).start();
}
}最后{
listener.close();
}
}
捕获(例外e)
{
常量.getInstance().getStatusLabel().setText(“服务器:此端口上已运行主机!”);
System.err.println(“服务器:此端口上已运行主机!”);
}
}
/**
*服务器侦听的端口。
*/
专用静态最终int端口=1337;
/**
*AppApplication main方法,它只侦听端口和
*生成处理程序线程。
*/
/**
*处理程序线程类。处理程序是从侦听线程派生的
*循环并负责与单个客户机进行交易
*并广播其信息。
*/
私有静态类处理程序扩展线程{
私有字符串名称;
专用插座;
中的私有缓冲区读取器;
私人打印输出;
私有对象输出流;
私有对象输出流输出;
/**
*构造一个处理程序线程,存储套接字。
*所有有趣的工作都是在run方法中完成的。
*/
公共处理程序(套接字){
this.socket=socket;
}
/**
*通过重复请求
*屏幕名称,直到提交了唯一的屏幕名称,然后
*确认该名称并为其注册输出流
*客户端在一个全局集合中,然后重复获取输入和
*广播他们。
*/
公开募捐{
试一试{
//为套接字创建对象流。
in=新的BufferedReader(新的InputStreamReader(
getInputStream());
out=新的PrintWriter(socket.getOutputStream(),true);
oin=newObjectInputStream(socket.getInputStream());
oout=newObjectOutputStream(socket.getOutputStream());
//将套接字添加到列表中
put(name,newconnectedUsers(name,oout));
System.err.println(users.size());
//接受来自此客户端的消息并广播它们。
//忽略无法广播到的其他客户端。
while(true){
Object obj=oin.readObject();
消息消息=(消息)对象;
if(obj.getClass().equals(Messages.class))
{
for(Map.Entry:users.entrySet())
{
ConnectedUsers user=entry.getValue();
user.objectWriter.writeObject(消息);
}
}
}
}捕获(IOException | ClassNotFoundException e){
系统输出打印ln(e);
}最后{
//此客户端正在关闭!请删除其名称和打印内容
//从集合中选择writer,然后关闭其套接字。
if(name!=null){
用户。删除(名称);
}
试一试{
socket.close();
}捕获(IOE异常){
}
}
}
}
}
name
似乎总是空的,所以您一直使用同一个键(空),这可以解释为什么地图中只有一个用户
还要注意,HashMap不是线程安全的——除非在从线程访问映射时添加某种形式的同步,否则它可能会产生令人惊讶的结果
您可以改为使用线程安全映射,例如ConcurrentHashMap。我明白您所说的这些优异结果的含义。谢谢你的帮助!