Alibaba cloud server communicates with multiple clients to designated users in java

preface

Purpose of this Code: as a door lock, raspberry pie has an id that uniquely identifies the door lock. In order to enable raspberry pie and app to communicate effectively with each other, tcp sockets are used. In order to easily identify the content of communication, the codes of the three are utf-8

java Server

theory

Write the server code in eclipse, package it into jar s, transfer it to Alibaba cloud server, and run it on the server.
A server first creates a main socket to accept and respond to client connection requests. After each client requests a connection, the server will generate a corresponding socket and create a thread to serve the client separately and send it to the corresponding client through the corresponding socket.
How to determine which socket corresponds to which client is the problem I encounter
The actual operation is: create a list to store a user class set by yourself. The class includes socket, socket input stream, socket output stream, and the id and type of lock required in this experiment. The id of the door lock user is the id of the door lock, the type is door, the id of the mobile phone user is the id of the login at that time (that is, the corresponding door lock id), and the type is man. This depends on the needs of your own application
Each time a client is added, a user is created and added to the list. The formal parameters of the thread are the user of the client and the list created earlier. When sending a message to a specified user, you can find it through the get function of the user class

Practical operation

user class:

class User {

	private String id;
	private String type;
	private Socket socket;
	private BufferedReader br;
	private PrintWriter pw;

	public User(String id, final Socket socket, String type) throws IOException {
		this.id = id;
		this.socket = socket;
		this.type = type;
		this.br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		this.pw = new PrintWriter(socket.getOutputStream());
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", type=" + type + ", socket=" + socket + ", br=" + br + ", pw=" + pw + "]";
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public Socket getSocket() {
		return socket;
	}

	public void setSocket(Socket socket) {
		this.socket = socket;
	}

	public BufferedReader getBr() {
		return br;
	}

	public void setBr(BufferedReader br) {
		this.br = br;
	}

	public PrintWriter getPw() {
		return pw;
	}

	public void setPw(PrintWriter pw) {
		this.pw = pw;
	}

}

Class of the server. The server uses the main function of serr as the entry of the program:

public class serr {

	public static void main(String[] args) throws Exception {
		// Instantiate a list to save all users
		List<User> list = new ArrayList<User>();
		list.clear();
		ServerSocket serverSocket = new ServerSocket(10001);
		while (true) {
			Socket socket = serverSocket.accept();
			//First create a user, id and type as the default values. After connecting, the client must log in and send its own id and type, otherwise it will be regarded as illegal and the user will disconnect
			User user = new User("id", socket, "type");
			list.add(user);
			System.out.println(socket);
			// Create a new thread, receive information and forward it. The thread needs user (can know the corresponding socket) and list (can know all sockets) as parameters
			ServerThread thread = new ServerThread(user, list);
			thread.start();
		}
	}
}

Thread:

class ServerThread extends Thread {

	private User user;
	private List<User> list;

	private boolean fristtime = true;  //Used to determine whether to send a message for the first time
	private boolean findother = true;  //Used to output how many sockets forwarded messages

	//constructor 
	public ServerThread(User user, List<User> list) {
		this.user = user;
		this.list = list;
	}

	public void run() {
		try {
			// Gets the printwriter of the client socket, which is used to send a successful connection message to the client
			PrintWriter pw = user.getPw();
			pw.write("hello" + "\n");
			pw.flush();
			InputStream in = user.getSocket().getInputStream(); // Get the message from the client
			// Read by byte because there are not only java clients, but also python clients. The clients do not send the operation of line conversion termination, so they cannot read a line with br readline
			int len = 0;
			byte[] buf = new byte[1024];
			while ((len = in.read(buf)) != -1) {
				// Format of information: login,id,type(door/man)
				// exit
				// say,totype(man,door),thing(open,add,abnormal)
				String msg = new String(buf, 0, len); // Convert to string
				String[] str = msg.split(",");//Separated by commas
				if (fristtime) {
				//Connect to the server for the first time
					if (str[0].equals("login")) {
					//Modify the id and type of the current user
						user.setId(str[1]);
						user.setType(str[2]);
						System.out.println("login seuccess");
						System.out.println("login" + user);
						fristtime = false;
					} else {
					//The first time you connect to the server, you don't report your id and type
						System.out.println("Illegal user!!");
						user.getBr().close();
						user.getSocket().close();
						break;
					}
				}
				System.out.println("client:" + user.getId() + "--" + user.getType() + ": " + msg);
				switch (str[0]) {
				case "login":
					System.out.println("ok,logined");
					break;
				case "exit":
					remove(user);// Remove User 
					break;
				case "say":
					sendToClient(user.getId(), str[1], str[2]); // Forwarding information to specific users can only be forwarded to users with the same id
					break;
				default:
					System.out.println("Illegal instruction:" + msg.toString());
					break;
				}
			}
		} catch (Exception e) {
			System.out.println("Accept instruction exception");
		} finally {
			try {
				user.getBr().close();
				user.getSocket().close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	private void sendToClient(String userid, String type, String instruction) {
		// Look it up from the beginning
		int number=0;
		for (User user : list) {
			if (user.getId().equals(userid) && user.getType().equals(type)) {
				findother=false;
				try {
					System.out.println("send to user" + user.getId() + "--" + user.getType() + ":" + instruction+". ");
					PrintWriter pw = user.getPw();
					//There are line transitions, so the client should use br readline to read by line
					pw.write(instruction + "\n");
					pw.flush();
					number++;
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		if(findother) {
			System.out.println("no con can send");
		}
		else {
			System.out.println("send tatal "+number+"clients!");
		}
	}

	private void remove(User user2) {
		list.remove(user2);
	}
}

Put the above three classes in a package and import the corresponding package
Finally, it is packaged into jar
Right click the project - Export - java - Runnable JAR file - next - select the location of the Export and the class where the program starts - finish

client

Android app

Grant application permission

It is very important to give the app networking permission before socket communication can be carried out. In androidmainfest Add in XML

<uses-permission android:name="android.permission.INTERNET"/>

Interface layout

You are free to copy this. There is no need to copy it. Here I randomly set two buttons to send messages and exit.
Remember to set the id for each button and other controls

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="send"
        tools:layout_editor_absoluteX="87dp"
        tools:layout_editor_absoluteY="122dp"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="exit"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/go"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="52dp"
        android:layout_marginLeft="52dp"
        android:layout_marginBottom="156dp"
        android:text="go"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

activity

Main

Declare required properties

    private String ip;
    private Socket socket;
    public static OutputStream os;
    public static BufferedReader br;
    Button one;
    Button exit;
    Button go;
    TextView tv;
    final int CONNECTING=1;
    final int CONNECT=2;
    int i=1;

In the current version, socket creation and connection need to be performed in asynchronous or Thread, not in the main Thread. Therefore, create a Thread class named TCPClient, which is a subclass of Thread.
If you want to update the ui of the interface, you need to modify it with handler
And start the service in the thread to receive information at any time

Thread establishing socket

    class tcpClient extends Thread {
        public void run() {
            Message message=handler.obtainMessage();
            message.what = CONNECTING;
            handler.sendMessage(message);
             Log.d("TAG", "handleMessage: try to connect");
             ip ="59.110.216.125" ;
            try {
                socket = new Socket(InetAddress.getByName(ip),10001);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (socket.isConnected()) {
                Message message1=handler.obtainMessage();
                message1.what = CONNECT;
                handler.sendMessage(message1);
                    Log.d("TAG", "handleMessage:connect");
                try {
                    os = socket.getOutputStream();
                    br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    String mine="login,lie1,man";
                    os.write(mine.getBytes());
                    os.flush();
                    System.out.println("send"+mine);

                    Intent startser=new Intent(MainActivity.this,recvservice.class);
                    startService(startser);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                }

        }
    }

handler

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == CONNECTING) {
                tv.setText("conning");
            }
            if (msg.what == CONNECT) {
                tv.setText("connect!");
            }
        }
    };

onCreate

In the onCreate function, you need to create and run a TCPClient thread and listen to the button click event:
It's better to put the content of the button click event outside the onCreate function, so that the code is more readable. I'm just testing here

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tcpClient tcp = new tcpClient();
        tcp.start();
        one=findViewById(R.id.button);
        exit=findViewById(R.id.button2);
        tv=findViewById(R.id.text);
        go=findViewById(R.id.go);
        go.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent();
                intent.setClass(MainActivity.this,testintentusesocket.class);
                startActivity(intent);
            }
        });
        exit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (socket.isConnected()) {
                    Thread sendthread=new sThread("exit");
                    sendthread.start();
                    finish();
                }
            }
        });
        one.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (socket.isConnected()) {
                    tv.setText("SEND OPEN"+i);
                    i++;
                    Thread sendthread=new sThread("say,door,open");
                    sendthread.start();
                }
                else{
                    tv.setText("NO CONNECT SOCKET");
                    Toast.makeText(MainActivity.this,"socket duankai",Toast.LENGTH_LONG);
                }

            }
        });
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        try {
            os.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

sThread

Among them, once the send or exit button is pressed, a thread is created to send data. It is easy to know that the thread sThread is used to send data. This thread is placed outside the MainActivity, so that other activities can also create sThread to send data

class sThread extends Thread {
    String msg;
    public sThread(String msg1)
    {
        msg=msg1;
    }
    public void run() {
        try {
            MainActivity.os.write(msg.getBytes());
            MainActivity.os.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }}

In my test, I found that the button listening event can not directly send information using the socket. A thread must be created to let the thread send information

Sum of main activities:

package com.example.servertest;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

class sThread extends Thread {
    String msg;
    public sThread(String msg1)
    {
        msg=msg1;
    }
    public void run() {
        try {
            MainActivity.os.write(msg.getBytes());
            MainActivity.os.flush();
            System.out.println("send open ");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }}

public class MainActivity extends AppCompatActivity {

    private String ip;
    private Socket socket;
    public static OutputStream os;
    public static BufferedReader br;
    Button one;
    Button exit;
    Button go;
    TextView tv;
    final int CONNECTING=1;
    final int CONNECT=2;
    int i=1;
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == CONNECTING) {
                tv.setText("conning");
            }
            if (msg.what == CONNECT) {
                tv.setText("connect!");
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tcpClient tcp = new tcpClient();
        tcp.start();
        one=findViewById(R.id.button);
        exit=findViewById(R.id.button2);
        tv=findViewById(R.id.text);
        go=findViewById(R.id.go);
        go.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent();
                intent.setClass(MainActivity.this,testintentusesocket.class);
                startActivity(intent);
            }
        });
        exit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (socket.isConnected()) {
                    Thread sendthread=new sThread("exit");
                    sendthread.start();
                    finish();
                }
            }
        });
        one.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (socket.isConnected()) {
                    tv.setText("SEND OPEN"+i);
                    i++;
                    Thread sendthread=new sThread("say,door,open");
                    sendthread.start();
                }
                else{
                    tv.setText("NO CONNECT SOCKET");
                    Toast.makeText(MainActivity.this,"socket duankai",Toast.LENGTH_LONG);
                }

            }
        });
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        try {
            os.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class tcpClient extends Thread {
        public void run() {
            Message message=handler.obtainMessage();
            message.what = CONNECTING;
            handler.sendMessage(message);
             Log.d("TAG", "handleMessage: try to connect");
             ip ="59.110.216.125" ;
            try {
                socket = new Socket(InetAddress.getByName(ip),10001);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (socket.isConnected()) {
                Message message1=handler.obtainMessage();
                message1.what = CONNECT;
                handler.sendMessage(message1);
                    Log.d("TAG", "handleMessage:connect");
                try {
                    os = socket.getOutputStream();
                    br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    String mine="login,lie1,man";
                    os.write(mine.getBytes());
                    os.flush();
                    System.out.println("send"+mine);

                    Intent startser=new Intent(MainActivity.this,recvservice.class);
                    startService(startser);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                }

        }
    }
}

testintentusesocket

Used to test whether the jump intent can communicate through the socket

Interface layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/buttont"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="send"
        tools:layout_editor_absoluteX="87dp"
        tools:layout_editor_absoluteY="122dp"
        tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>

Activity code

package com.example.servertest;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;


public class testintentusesocket extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.te);
        Button bt=findViewById(R.id.buttont);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Thread sendthread=new sThread("open");
                sendthread.start();
                finish();
            }
        });

    }
}

Configure activities

In Android mainfest Add in XML

<activity android:name=".testintentusesocket"></activity>

service

Create a thread in oncreate to listen for messages at any time

package com.example.servertest;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class recvservice extends Service {

    @Override
    public IBinder onBind(Intent intent){
        return  null;
    }
    @Override
    public void onCreate(){
        super.onCreate();
        new Thread((new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("lisen......");
                    while(true){
                        String read=MainActivity.br.readLine();
                        System.out.println(read);
                        if(read.equals("abnormal")){
                            System.out.println("recive abnormal! ");
                        }
                    }

                }catch (Exception e){
                    System.out.println("read error!");
                }

            }
        })).start();
    }
    @Override
    public int onStartCommand(Intent intent,int flags,int startId){
        return super.onStartCommand(intent,flags,startId);
    }
    @Override
    public void onDestroy(){
        super.onDestroy();
        System.out.println("oncreate service");
    }
}

In mainfest The service is declared in XML

 <service android:name=".recvservice"/>

Raspberry pie

Create a thread to respond to messages in real time, do your own things in the main thread and send messages

import socket
import time
import threading

#tcp connection before running the program
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "59.110.216.125"  # Public IP address of alicloud server
port = 10001  # The port opened in the ECS console security group is the same as the server
s.connect((host, port))  # Create connection

showconn=True

#The door lock sends a message (abnormal) to the server
def send(msg):
   print(s)
   s.send(msg.encode("utf-8"))

#The door lock is ready to accept the message: open the door
def recvthing():
   while showconn:
       data = s.recv(20)
       //Due to the server forwarding, there is a transfer
       data = data.decode("utf-8").strip('\n')
       if data=="hello":
           print("connect!")
       if data=="open":
           print("to opendoordef()")
       if data=="add":
           print("to addfgdef()")
       print(data)
   s.close()

if __name__ == '__main__':
   #Create a thread and let the thread stand by to receive information
   t = threading.Thread(target=recvthing)
   t.start()
   #Send the id of the door lock to the server first, and let the server store the door lock id, socketnumber and type=2 as the door lock in the database
   msg = 'login,lie1,door'
   send(msg)
   while True:
       sendthing = input()
       send(sendthing)

Keywords: Python Java Android server

Added by smilley654 on Wed, 26 Jan 2022 23:32:48 +0200