套接字服务器可行性

时间:2014-06-23 17:20:37

标签: java sockets

我为Android客户端设计了一个Socket基础服务器,它接收请求并处理mysql数据库,现在我希望每小时约2000个请求,我想知道这个服务器是否适用于该数量甚至更多?有什么别的东西或任何更好的协议我应该使用而不是socket来处理更大的请求,但是ThreadPoolExecutor?

 public class Server {
// a unique ID for each connection
private static int uniqueId;
// an ArrayList to keep the list of the Client
private ArrayList<ClientThread> al;
// if I am in a GUI
private ServerGUI sg;
// to display time
private SimpleDateFormat sdf;
// the port number to listen for connection
private int port;
// the boolean that will be turned of to stop the server
private boolean keepGoing;
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
static final String DB_URL = "jdbc:mysql://localhost:3306/openfire";
static final String USER = "admin";
static final String PASS = "admin";
static boolean jobdone = false;
protected ServerSocket serverSocket = null;
protected boolean      isStopped    = false;
protected Thread       runningThread= null;


Connection conn = null;
Statement stmt = null;

public Server(int port) {

    this(port, null);
}

public Server(int port, ServerGUI sg) {

    this.sg = sg;

    this.port = port;

    sdf = new SimpleDateFormat("HH:mm:ss");

    al = new ArrayList<ClientThread>();
}

public void start() throws InterruptedException {
    keepGoing = true;
    try 
    {

        // the socket used by the server
        ServerSocket serverSocket = new ServerSocket(port);

        // infinite loop to wait for connections
        while(keepGoing) 
        {
            // format message saying we are waiting
            display("Server waiting for Clients on port " + port + 
 ".");

            Socket socket = serverSocket.accept();      // accept 
  connection
            // if I was asked to stop

            if(!keepGoing)
                break;
            ClientThread t = new ClientThread(socket);  // make a 
  thread of it
            jobdone=false;

 al.add(t);                                 // save 
 it in the ArrayList
            t.start();
        }
        // I was asked to stop
        try {
            serverSocket.close();
            for(int i = 0; i < al.size(); ++i) {
                ClientThread tc = al.get(i);
                try {
                tc.sInput.close();
                tc.sOutput.close();
                tc.socket.close();
                }
                catch(IOException ioE) {
                    // not much I can do
                }
            }
        }
        catch(Exception e) {
            display("Exception closing the server and clients: " + e);
        }
    }
    // something went bad
    catch (IOException e) {
        String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e   
 +  "\n";
        display(msg);
    }
}       
/*
 * For the GUI to stop the server
 */
protected void stop() {
    keepGoing = false;
    // connect to myself as Client to exit statement 
    // Socket socket = serverSocket.accept();
    try {
        new Socket("localhost", port);
    }
    catch(Exception e) {
        // nothing I can really do
    }
}
/*
 * Display an event (not a message) to the console or the GUI
 */
private void display(String msg) {
    String time = sdf.format(new Date()) + " " + msg;
    if(sg == null)
        System.out.println(time);
    else
        sg.appendEvent(time + "\n");
}

    // create a server object and start it



 public static void shutdown() {
jobdone = true;


 }
/** One instance of this thread will run for each client */

   class ClientThread extends Thread {
    // the socket where to listen/talk
    String Type;
    Socket socket;
    ObjectInputStream sInput;
    ObjectOutputStream sOutput;
    // my unique id (easier for deconnection)
    int id;

    String encrypted = "'adomgaldkopnfaosdppkdsad'";


    // Constructore
    ClientThread(Socket socket) throws InterruptedException {
        // a unique id
        id = ++uniqueId;
        this.socket = socket;
        /* Creating both Data Stream */
        System.out.println("Thread trying to create Object Input/Output 
 Streams");
    while (!jobdone){
        try
        {
            // create output first
            sOutput = new ObjectOutputStream(socket.getOutputStream());
            sInput  = new ObjectInputStream(socket.getInputStream());
            // read the username


            String RegisterRequest = (String) sInput.readObject();  

            String[] result = RegisterRequest.split("\\,");
            String theuser = result[0];
            display("theuser="+theuser);
            String thepass = result[1];
            display("thepass="+thepass);
            String thename = result[2];   
            display("thename="+thename);
            String themail = result[3];
            display("themail="+themail);
            String thephone = result[4];
            display("thephone="+thephone);
            String newRID = result[5];
            display("RID="+newRID);



            String OldRID=newRID;
            try{
                  //STEP 2: Register JDBC driver
                  Class.forName("com.mysql.jdbc.Driver");

                  //STEP 3: Open a connection
                  System.out.println("Connecting to a selected 
 database...");
                  conn = DriverManager.getConnection(DB_URL, USER, 
 PASS);
                  System.out.println("Connected database 
 successfully...");

                  String selectSQL1 = "SELECT username FROM ofuser 
 WHERE username= '"+theuser+"'";
                  PreparedStatement preparedStatement = 
 conn.prepareStatement(selectSQL1);
                  ResultSet usernameRS = 
 preparedStatement.executeQuery(selectSQL1);


                  if (!usernameRS.next()){



                  //STEP 4: Execute a query
                  System.out.println("Inserting records into the  
 table...");
                  stmt = conn.createStatement();

                  String sql = "INSERT INTO ofuser VALUES 

('"+theuser+"','"+thepass+"',null,'"+thename+"','"+themail+"',
'"+4234+"','"+23432+"','"+the
 phone+"','"+null+"','"+null+"')";
                  stmt.executeUpdate(sql);
                     Type="T"; 
                  String REresponse ="('"+Type+"','"+OldRID+"')";
                  System.out.println(REresponse);
                  sOutput.writeObject(REresponse);
                  sOutput.flush();
                  //  sOutput.writeObject(Type);
                  System.out.println("SUCCESS");
                  }else{ 

                      Type="F";
                    String REresponse ="('"+Type+"','"+OldRID+"')";
                    Type="F";   
                            sOutput.writeObject(REresponse);
                            sOutput.flush();
                            System.out.println("FAIL");
                  }



                  return;




              }catch(SQLException se){
                  //Handle errors for JDBC
                  se.printStackTrace();
               }catch(Exception e){
                  //Handle errors for Class.forName
                  e.printStackTrace();
               }finally{
                  //finally block used to close resources
                  try{
                     if(stmt!=null)
                        conn.close();
                  }catch(SQLException se){
                  }// do nothing
                  try{
                     if(conn!=null)
                        conn.close();
                  }catch(SQLException se){
                     se.printStackTrace();
                  }//end finally try
            }
               }//end try






        catch (IOException e) {
            display("Exception creating new Input/output Streams: " + 
 e);
            return;
        }
        // have to catch ClassNotFoundException
        // but I read a String, I am sure it will work
        catch (ClassNotFoundException e) {
        }
        Thread.sleep(5000);
        Server.shutdown();
    }

   }
    // what will run forever

        // remove myself from the arrayList containing the list of the
        // connected Clients
    public void main(String[] args) throws InterruptedException {
        // start server on port 1500 unless a PortNumber is specified 
        int portNumber = 1500;
        switch(args.length) {
            case 1:
                try {
                    portNumber = Integer.parseInt(args[0]);
                }
                catch(Exception e) {
                    System.out.println("Invalid port number.");
                    System.out.println("Usage is: > java 
  Server [portNumber]");
                    return;
                }
            case 0:
                break;
            default:
                System.out.println("Usage is: > java Server  
 [portNumber]");
                return;

        }
        // create a server object and start it
        Server server = new Server(portNumber);
        server.start();
    }







    // try to close everything
    private void close() {
        // try to close the connection
        try {


            if(sOutput != null) sOutput.close();
        }
        catch(Exception e) {}
        try {
            if(sInput != null) sInput.close();
        }
        catch(Exception e) {};
        try {
            if(socket != null) socket.close();
        }
        catch (Exception e) {}
    }

    /*
     * Write a String to the Client output stream
     */
    private boolean writeMsg(String msg) {
        // if Client is still connected send the message to it
        if(!socket.isConnected()) {
            close();
            return false;
        }
        // write the message to the stream
        try {
            sOutput.writeObject(msg);
        }
        // if an error occurs, do not abort just inform the user
        catch(IOException e) {
            display("Error sending message to " );
            display(e.toString());
        }
        return true;
    }
}



//public void main(String[] args) {


    //   System.out.println("Goodbye!");
//  }//end main




 }

2 个答案:

答案 0 :(得分:1)

2000每小时约为0.55每秒。您应该能够在作为服务器运行的移动电话上处理该速率(假设请求不复杂)

如果您需要处理最多100K连接和每小时超过10亿个请求,TCP可能会很好。如果你想要更多,你可以使用UDP,或购买第二台服务器。更多服务器可能更简单;)

注意:您的数据库和/或网络带宽可能会在TCP服务器出现之前很长时间内完成。

答案 1 :(得分:0)

要注意高ram的使用情况,似乎你每次请求都要创建如此多的对象...... 我的建议是你应该创建有限数量的对象(例如100)然后将它们放入 ArrayList 然后分别调用它们,我的意思是:

public static void startServer() {
    try {
        final ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(12345);
        final List<Operator> operators = new ArrayList<>();
        final int nOperators = /* your choice */;
        for (int i = 0; i < nOperators; i++) {
            operators.add(i, new Operator());
        }
        final int parallelism = Runtime.getRuntime().availableProcessors();
        ForkJoinPool pool = new ForkJoinPool(parallelism);
        pool.submit(() -> new Thread(() -> {
            int i = 0;
            while (true) {
                try {
                    operators.get(i).newOperation(serverSocketChannel.accept());
                    i++;
                    if (i == nOperators) {
                        i = 0;
                    }
                } catch (IOException ignored) {
                }
            }
        })).fork().invoke().start();
    } catch (IOException ignored) {
    }
}

然后你会看到速度和性能的巨大提升......

编辑:

例如:

public class Operator {

    public void newOperation(final SocketChannel socketChannel) throws IOException {
        DataInputStream dis = new DataInputStream(socketChannel.socket().getInputStream());
        DataOutputStream dos = new DataOutputStream(socketChannel.socket().getOutputStream());
        //TODO something here
        dis.close();
        dos.close();
        socketChannel.close();
    }

}

有关 ServerSocketChannel SocketChannel ForkJoinPool

的更多信息 祝你好运:)


@PeterLawrey编辑这是我可以写它的方式,假设我有很多与CPU密集型操作的短暂连接。如果您有阻止网络/ IO的操作,您可能需要更多线程。由于您需要普通IO,因此坚持使用普通IO是有意义的。

public static void startServer() throws IOException {
    // don't ignore the server failing to bind.
    final ServerSocket ss = new ServerSocket(12345);

    final int parallelism = Runtime.getRuntime().availableProcessors();
    // add one for the acceptor
    final ExecutorService pool = ExecutorService.newFixedThreadPool(parallelism+1);

     pool.submit(() -> {
         try {
             while (!ss.isClosed())
                 pool.submit(new Handler(serverSocketChannel.accept()));
         } catch (IOException ignored) {
     });
}

class Handler implements Runnable {
   static final ThreadLocal<ExpensiveObject> expensiveObjectIWantToReuse = new ThreadLocal<>();

   final Socket s;
   final DataInputStream in;
   final DataOutputStream out;

   Handler(Socket s) {
      this.s = s;
      this.in = new DataInputStream(new BufferedInputStream(s.getInputStream()));
      this.out = new DataOutputStream(new BufferedOutputStream(s.getOutputStream()));
   }

   public void run() {
      try {
          processStream(in, out);
      } catch (Throwable t) {
          // log t
      } finally (
          close(out);  // also flush()es
          close(in);
          close(s);
      }
   }

   public static void close(Closable c) {
      try {
          if (c != null) c.close();
      } catch (IOException ignored) { }
   }

   protected void processStream(DataInput di, DataOutput out) {
      // do something
   }

}