我为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
}
答案 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
}
}