套接字将多个客户端编程到一台服务器
Posted
技术标签:
【中文标题】套接字将多个客户端编程到一台服务器【英文标题】:socket programming multiple client to one server 【发布时间】:2012-04-25 06:13:51 【问题描述】:如何处理多个客户端连接到一台服务器?我有这个 LogServer.java
import javax.net.ssl.*;
import javax.net.*;
import java.io.*;
import java.net.*;
public class LogServer
private static final int PORT_NUM = 5000;
public static void main(String args[])
ServerSocketFactory serverSocketFactory =
ServerSocketFactory.getDefault();
ServerSocket serverSocket = null;
try
serverSocket =
serverSocketFactory.createServerSocket(PORT_NUM);
catch (IOException ignored)
System.err.println("Unable to create server");
System.exit(-1);
System.out.printf("LogServer running on port: %s%n", PORT_NUM);
while (true)
Socket socket = null;
try
socket = serverSocket.accept();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(is, "US-ASCII"));
String line = null;
while ((line = br.readLine()) != null)
System.out.println(line);
catch (IOException exception)
// Just handle next request.
finally
if (socket != null)
try
socket.close();
catch (IOException ignored)
和一个嵌入的小程序,其中部分代码像这样,例如
import java.io.*;
import java.util.logging.*;
public class LogTest
private static Logger logger = Logger.getAnonymousLogger();
public static void main(String argv[]) throws IOException
Handler handler = new SocketHandler("localhost", 5000);
logger.addHandler(handler);
logger.log(Level.SEVERE, "Hello, World");
logger.log(Level.SEVERE, "Welcome Home");
logger.log(Level.SEVERE, "Hello, World");
logger.log(Level.SEVERE, "Welcome Home");
现在的问题是,如果我在服务器上运行“java LogServer”,它将打开应用程序并等待输入流,如果我打开我的站点,它将开始流式传输日志。但是,如果我使用其他计算机/网络再打开一个,则第二个站点不会记录流。似乎是因为第一个仍然绑定到端口 5000。
我该如何处理? 套接字实际上如何与多个客户端/一个服务器一起工作?
【问题讨论】:
【参考方案1】:对于每个客户端,您需要启动单独的线程。示例:
public class ThreadedEchoServer
static final int PORT = 1978;
public static void main(String args[])
ServerSocket serverSocket = null;
Socket socket = null;
try
serverSocket = new ServerSocket(PORT);
catch (IOException e)
e.printStackTrace();
while (true)
try
socket = serverSocket.accept();
catch (IOException e)
System.out.println("I/O error: " + e);
// new thread for a client
new EchoThread(socket).start();
和
public class EchoThread extends Thread
protected Socket socket;
public EchoThread(Socket clientSocket)
this.socket = clientSocket;
public void run()
InputStream inp = null;
BufferedReader brinp = null;
DataOutputStream out = null;
try
inp = socket.getInputStream();
brinp = new BufferedReader(new InputStreamReader(inp));
out = new DataOutputStream(socket.getOutputStream());
catch (IOException e)
return;
String line;
while (true)
try
line = brinp.readLine();
if ((line == null) || line.equalsIgnoreCase("QUIT"))
socket.close();
return;
else
out.writeBytes(line + "\n\r");
out.flush();
catch (IOException e)
e.printStackTrace();
return;
您还可以使用更高级的解决方案,使用 NIO 选择器,因此您不必为每个客户端创建线程,但这有点复杂。
【讨论】:
nodejs 不会为每个客户端创建线程,你是说 nodejs 使用 NIO 选择器吗? 是否有理由使用\n\r
而不是\r\n
?
我看到你定义了一个端口号为final int,这是否意味着每个服务器线程都在同一个端口?
那你如何使用JUnit测试来测试呢?【参考方案2】:
这是处理多个客户端的回显服务器...使用线程运行良好且良好
// echo server
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server_X_Client
public static void main(String args[])
Socket s=null;
ServerSocket ss2=null;
System.out.println("Server Listening......");
try
ss2 = new ServerSocket(4445); // can also use static final PORT_NUM , when defined
catch(IOException e)
e.printStackTrace();
System.out.println("Server error");
while(true)
try
s= ss2.accept();
System.out.println("connection Established");
ServerThread st=new ServerThread(s);
st.start();
catch(Exception e)
e.printStackTrace();
System.out.println("Connection Error");
class ServerThread extends Thread
String line=null;
BufferedReader is = null;
PrintWriter os=null;
Socket s=null;
public ServerThread(Socket s)
this.s=s;
public void run()
try
is= new BufferedReader(new InputStreamReader(s.getInputStream()));
os=new PrintWriter(s.getOutputStream());
catch(IOException e)
System.out.println("IO error in server thread");
try
line=is.readLine();
while(line.compareTo("QUIT")!=0)
os.println(line);
os.flush();
System.out.println("Response to Client : "+line);
line=is.readLine();
catch (IOException e)
line=this.getName(); //reused String line for getting thread name
System.out.println("IO Error/ Client "+line+" terminated abruptly");
catch(NullPointerException e)
line=this.getName(); //reused String line for getting thread name
System.out.println("Client "+line+" Closed");
finally
try
System.out.println("Connection Closing..");
if (is!=null)
is.close();
System.out.println(" Socket Input Stream Closed");
if(os!=null)
os.close();
System.out.println("Socket Out Closed");
if (s!=null)
s.close();
System.out.println("Socket Closed");
catch(IOException ie)
System.out.println("Socket Close Error");
//end finally
这里也是客户端的代码。只要你想创建多个客户端,执行这段代码就可以了。
// A simple Client Server Protocol .. Client for Echo Server
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class NetworkClient
public static void main(String args[]) throws IOException
InetAddress address=InetAddress.getLocalHost();
Socket s1=null;
String line=null;
BufferedReader br=null;
BufferedReader is=null;
PrintWriter os=null;
try
s1=new Socket(address, 4445); // You can use static final constant PORT_NUM
br= new BufferedReader(new InputStreamReader(System.in));
is=new BufferedReader(new InputStreamReader(s1.getInputStream()));
os= new PrintWriter(s1.getOutputStream());
catch (IOException e)
e.printStackTrace();
System.err.print("IO Exception");
System.out.println("Client Address : "+address);
System.out.println("Enter Data to echo Server ( Enter QUIT to end):");
String response=null;
try
line=br.readLine();
while(line.compareTo("QUIT")!=0)
os.println(line);
os.flush();
response=is.readLine();
System.out.println("Server Response : "+response);
line=br.readLine();
catch(IOException e)
e.printStackTrace();
System.out.println("Socket read Error");
finally
is.close();os.close();br.close();s1.close();
System.out.println("Connection Closed");
【讨论】:
【参考方案3】:我想问题是你需要为每个连接启动一个单独的线程并在循环中调用serverSocket.accept()
以接受多个连接。
在同一个端口上有多个连接不是问题。
【讨论】:
【参考方案4】:请参阅 O'Reilly “Java Cookbook”,Ian Darwin - 食谱 17.4 Handling Multiple Clients。
注意accept()
不是线程安全的,所以调用被包裹在synchronized
中。
64: synchronized(servSock)
65: clientSocket = servSock.accept();
66:
【讨论】:
【参考方案5】:这是多个客户端到一个服务器工作正常的代码.. 试试看:)
Server.java:
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
class Multi extends Thread
private Socket s=null;
DataInputStream infromClient;
Multi() throws IOException
Multi(Socket s) throws IOException
this.s=s;
infromClient = new DataInputStream(s.getInputStream());
public void run()
String SQL=new String();
try
SQL = infromClient.readUTF();
catch (IOException ex)
Logger.getLogger(Multi.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Query: " + SQL);
try
System.out.println("Socket Closing");
s.close();
catch (IOException ex)
Logger.getLogger(Multi.class.getName()).log(Level.SEVERE, null, ex);
public class Server
public static void main(String args[]) throws IOException,
InterruptedException
while(true)
ServerSocket ss=new ServerSocket(11111);
System.out.println("Server is Awaiting");
Socket s=ss.accept();
Multi t=new Multi(s);
t.start();
Thread.sleep(2000);
ss.close();
Client1.java:
import java.io.DataOutputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
public class client1
public static void main(String[] arg)
try
Socket socketConnection = new Socket("127.0.0.1", 11111);
//QUERY PASSING
DataOutputStream outToServer = new DataOutputStream(socketConnection.getOutputStream());
String SQL="I am client 1";
outToServer.writeUTF(SQL);
catch (Exception e) System.out.println(e);
Client2.java
import java.io.DataOutputStream;
import java.net.Socket;
public class client2
public static void main(String[] arg)
try
Socket socketConnection = new Socket("127.0.0.1", 11111);
//QUERY PASSING
DataOutputStream outToServer = new DataOutputStream(socketConnection.getOutputStream());
String SQL="I am Client 2";
outToServer.writeUTF(SQL);
catch (Exception e) System.out.println(e);
【讨论】:
你好 Usama,这两个客户端可以在同一台电脑上吗?! @asma,是的。两个客户端都可以在同一台机器上运行。许多客户端可以在单台机器或多台机器上运行。以上是关于套接字将多个客户端编程到一台服务器的主要内容,如果未能解决你的问题,请参考以下文章
zeromq 模式,用于多客户端从一台服务器推送套接字拉接收