我刚从好奇心开始使用Java套接字。
我写了一小段代码,一个服务器和一个客户端。
服务器接受一个字符串并将其转换为大写字母并返回给客户端。
我希望服务器能够处理多个客户端并具有持久连接。
这是服务器代码:
package 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;
import java.net.SocketException;
import java.util.ArrayList;
public class Server {
private ServerSocket listener;
private ArrayList<Socket> clients;
public Server() throws IOException{
clients = new ArrayList<Socket>();
listener = new ServerSocket(7575);
}
public Server(int port) throws IOException{
clients = new ArrayList<Socket>();
listener = new ServerSocket(port);
}
public void start() throws IOException, InterruptedException{
Thread one = new Thread(){
public void run(){
while (true){
Socket socket = null;
try {
socket = listener.accept();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (socket.isConnected()){
try {
socket.setKeepAlive(true);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clients.add(socket);
System.out.println(socket.getRemoteSocketAddress().toString());
}
}
}
};
Thread two = new Thread(){
public void run(){
try {
while (true){
work();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
one.start();
two.start();
one.join();
two.join();
stop();
}
private void stop() throws IOException{
listener.close();
}
private void work() throws IOException{
if (clients.size() == 0){
return;
}
for(int i = 0; i < clients.size(); i++){
Socket socket = clients.get(i);
if (!socket.isClosed()){
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
String data = br.readLine();
if (data == null) continue;
out.println(data.toUpperCase());
}
else{
clients.remove(socket);
}
}
}
}
package entry;
import java.io.IOException;
import server.Server;
public class Main {
public static void main(String args[]) throws IOException{
Server server = new Server();
try {
server.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这是客户:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Main {
public static void main(String args[])throws IOException{
Socket socket = new Socket("192.168.0.110", 7575);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedReader sr = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pr = new PrintWriter(socket.getOutputStream(), true);
while (true){
System.out.println("\n\nEnter a string : ");
String inp = br.readLine();
if (inp.equals("quit")) break;
pr.println(inp);
System.out.println("The response is : " + sr.readLine());
}
socket.close();
}
}
奇怪的是,当我在服务器代码中设置断点并逐步执行eclipse中的代码时,代码完全按预期工作,即我在客户端获得响应。
但是当我直接在eclipse中运行它时,我没有得到客户端的响应。
无法理解出了什么问题。
修改的
我似乎解决了这个问题。
以下是代码段:
Thread two = new Thread(){
public void run(){
try {
while (true){
Thread.sleep(1000); //This is the added line
work();
}
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
但是我仍然对于什么使时间差异感到困惑。 有没有更清洁的方法来实现这一目标?
答案 0 :(得分:1)
我用不同的方法解决了这个问题。
以下是新方法:
ServerHandler.java:
package server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
public class ServerHandler extends Thread{
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private ArrayList<Socket> clients;
public ServerHandler(Socket socket) throws IOException{
this.socket = socket;
clients = new ArrayList<Socket>();
if (!clients.contains(socket)){
clients.add(this.socket);
System.out.println(this.socket.getRemoteSocketAddress());
}
}
@Override
public void run(){
while (true){
if (clients.isEmpty()) break;
String str = null;
for (int i = 0; i < clients.size(); i++){
Socket socket = clients.get(i);
if (socket.isClosed()){
clients.remove(socket);
continue;
}
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
out = new PrintWriter(socket.getOutputStream(), true);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
str = in.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.println(str.toUpperCase());
}
}
}
}
Main.java [用于运行服务器]:
package entry;
import java.io.IOException;
import java.net.ServerSocket;
import server.ServerHandler;
public class Main {
public static void main(String args[]) throws IOException{
ServerSocket listener = new ServerSocket(7575);
try{
while (true){
new ServerHandler(listener.accept()).start();
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
listener.close();
}
}
}
答案 1 :(得分:1)
好的,我们走了。我不理解使用Arraylist
来维护连接,除非您正在处理每个Client
的混乱细节。
一次处理多个客户端的最常用或首选方法可以通过示例来理解:
import java.net.ServerSocket;
import java.io.IOException;
class Server {
public static void main(String[] args) throws IOException {
try( ServerSocket ss = new ServerSocket(3333)) { // try with resources
new ServerThread(ss.accept()).start();
}
}
}
正如您所看到的,我刚刚定义了一个将侦听客户端连接的类,并且一旦向服务器发出请求,它将启动一个在下一个类中定义的Thread。这里要注意的一点是使用Try-with-Resources
块。任何实现Closeable
接口的类都可以包含在此try语句中。 try-with-resources会自动为我关闭流或连接。这意味着,您从代码中删除了所有冗余的try-catch
块,并改为使用此try
。
现在,
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerThread extends Thread {
Socket s = null;
public ServerThread(Socket s) {
super("ServerThread");
this.s = s;
}
public void run() {
try( PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
BufferedReader stream = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedReader write = new BufferedReader(new InputStreamReader(System.in))) {
System.out.println("In Server");
String in, out;
while ((in = stream.readLine()) != null) {
System.out.println("Msg 4m client: " + in);
if(in.equals("bye"))
break;
out = write.readLine();
pw.println(out);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
在这里观察try-with-resources
语句,我们可以在这里初始化多个Connections / Input-Output Streams,一旦编译器从try
语句返回,所有打开的连接将自动关闭.Also ,观察while
语句,它将一直运行直到客户端发送消息,并且如果消息是"bye"
则退出。
最后,一个向服务器发送请求的客户端程序。
import java.net.Socket;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
class Client {
public static void main(String[] args) {
try( Socket s = new Socket("localhost", 3333);
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
BufferedReader stream = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedReader write = new BufferedReader(new InputStreamReader(System.in)) ) {
System.out.println("In Client");
String in;
while ((in = write.readLine()) != null) {
pw.println(in);
if(in.equals("bye"))
break;
System.out.println("Msg 4m server: " + stream.readLine());
}
} catch(IOException e) {
System.err.println("Exception: " + e);
}
}
}
注意,这里的while
语句将循环直到用户输入消息,如果消息是&#34; bye&#34;,它将退出。程序的恢复可以很容易理解从上面的解释。