我正在创建一个Android客户端,我想确保它可以连接到Java服务器。
我的服务器就是这个
public static void main(String[] args){
int portNumber = 5885;
System.out.println("Starting..");
// We use a try-with-resources statement to ensure that all sockets and
// readers/writers are closed when the program terminates
try (
// Set up the server socket on a specified port number
ServerSocket serverSocket = new ServerSocket(portNumber);
// Wait until a connection is made by a client and accept its socket
Socket clientSocket = serverSocket.accept();
// Set up a writer to the client socket
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
// Set up a reader from the client socket
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
) {
// Missing Part
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port " + portNumber + " or listening for a connection");
System.out.println(e.getMessage());
}
}
}
并且客户端正在尝试连接此代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.board_layout);
new Thread(new ClientThread()).start();
}
class ClientThread implements Runnable {
@Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
如何检查是否有人连接到服务器?用
if (clientSocket != null)
System.out.println("Someone is in");
还是什么?
答案 0 :(得分:1)
在Socket clientSocket = serverSocket.accept();
之后放一个打印声明。方法ServerSocket#accept
将阻止执行,直到客户端被接受为止,这意味着accept
之后的打印语句只会在客户端被接受时触发。
try(ServerSocket server = new ServerSocket(5885)) {
while(true) {
try {
Socket socket = server.accept();
System.out.println("Client accepted!");
} catch(IOException e) {
e.printStackTrace(); // error accepting client
}
}
} catch(IOException e) {
e.printStackTrace(); // error starting server
}
您需要为每个用户分配唯一的ID。然后,您需要一个数据结构来存储每个用户 - 一个允许您根据ID获取用户的用户可能是首选(Map
可行)。
生成UUID
,然后将Socket
存储在允许您使用密钥访问值的数据结构中(在本例中为UUID
。
class Server {
private static final Map<UUID, Socket> CONNECTIONS = new HashMap<>();
public static void main(String[] args) {
try(ServerSocket server = new ServerSocket(5885)) {
while(true) {
try {
Socket socket = server.accept();
UUID uniqueId = UUID.randomUUID();
CONNECTIONS.put(uniqueId, Socket);
} catch(IOException e) {
e.printStackTrace(); // error accepting client
}
}
} catch(IOException e) {
e.printStackTrace(); // error starting server
}
}
public static boolean userExists(UUID uniqueId) {
return CONNECTIONS.containsKey(uniqueId);
}
}
您也可以使用用户名执行此操作。或者更好的是,创建一个由Socket
,UUID
和String username;
组成的自己的类型:
class User {
private Socket socket;
private UUID uniqueId;
private String username;
// constructor, getters, behaviors
}
维持List
User
而不是Map<UUID, Socket>
:
List<User> users = new ArrayList<>();
当您需要检查列表时,请将其转换为您要检查的属性的List
:
String nameOfUser = ...;
boolean containsUser= users.stream().map(User::getUsername).anyMatch(name -> name.equals(nameOfUser));
这假定User
有getUsername()
方法。 UUID
也可以这样做。
答案 1 :(得分:1)
如果您想知道客户端是否已连接,serverSocket.accept()
将阻止,直到有人连接。这也应该在为每个客户端生成专用线程的循环中。
如果您想要可靠地确认客户端已连接,我会使用心跳(来自客户端的消息,其目的是确认连接的状态):
让每个客户端向服务器发送心跳。例如,在客户端有一个线程,它会休眠一段时间(10秒),然后唤醒以发送心跳。这样,如果您在一段时间内没有收到心跳,则表示存在连接问题。
只是为了说明这个概念:
服务器:
public void startServer() throws IOException{
ServerSocket serverSocket = new ServerSocket(9209);
List<ClientThread> clientThreads = new ArrayList<ClientThread>();
boolean running = true;
while(running){
try {
Socket clientSocket = serverSocket.accept();
ClientThread clientThread = new ClientThread(clientSocket);
clientThread.run();
clientThreads.add(clientThread);
} catch (IOException e) {
e.printStackTrace();
}
}
for(ClientThread thread : clientThreads){
thread.shutdown();
}
}
public class ClientThread extends Thread{
private BufferedReader in;
private volatile boolean running = true;
private long lastHeartBeat;
public ClientThread(Socket socket) throws IOException{
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
public void shutdown(){
running = false;
}
@Override
public void run() {
while(running){
try {
if(in.readLine().equalsIgnoreCase("HeartBeat")){
lastHeartBeat = System.currentTimeMillis();
}else{
//do something else
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
每个客户端都会创建以下内容之一:
public class HeartBeatThread extends Thread{
PrintWriter out;
volatile boolean running = true;
public HeartBeatThread(Socket socket) throws IOException{
this.out = new PrintWriter(socket.getOutputStream(), true);
}
public void shutdown(){
running = false;
}
@Override
public void run() {
while(running){
try {
sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
out.println("HeartBeat");
}
}
}