socket java实现 byte_Python与Java实现Socket通信!

  • Post author:
  • Post category:java



二、Socket通信的实现

为CreateSocketConnection填充内容,建立socket连接:

  • Python资源共享群:626017123
public class MainActivity extends AppCompatActivity {
    // 创建全局变量方便重复使用
    Socket socket;
    InputStream is;
    OutputStream os;
    // ...
    // 省略之前的内容
    // ...
    public boolean CreateSocketConnection() {
        try {
            // 1. 构建socket
            String host = "192.168.0.104";
            int port = 8000;
            socket = new Socket(host, port);
            // 2. 构建I/O
            is = socket.getInputStream();
            os = socket.getOutputStream();
            // 3.1 向服务器端发送信息
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
            String str = "Hello!"
            bw.write(str);
            bw.flush();
            // 3.2 读取服务器返回的消息
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String return_str = br.readLine(); // *readLine方法
            System.out.println(return_str)
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    public boolean RemoveSocketConnection() {
        try {
            // 4.1 关闭I/O
            is.close();
            os.close();
            // 4.2 关闭socket
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

注意几点:

1.

构建socket

与python的几乎没有差别,直接new一个Socket对象就成。

2.

构建I/O

使用socket对象的getInputStream, getOutputStream方法,获取到InputStream, OutputStream类型的字节流

3.

包装字节流对象

由于不想自己手动实现字节流的转换,所以我对得到的流利用BufferedWriter, BufferedReader进行包装,并利用其中的方法便捷地写入/读取字符串数据。这里实现方法很多,我最后选择了这种BufferedWriter的写法。

了解更多方法可参阅这篇文章:Java中将InputStream读取为String, 各种方法的性能对比[1]。


注意:

readLine方法必须要求发送来的字符串以换行符结尾。

4.

关闭对象

自己产生的对象自己关掉,不要乱丢垃圾。操作也很简单,直接调用对象的close方法即可。

这样就实现了完整的一轮通信:先打开服务端,再在手机端点击链接按钮,你就会看到两端的信息已经交换。


三、进一步完善:添加连接验证

这一步不是必要的,但是对于理解和利用通信机制很有好处,因此我添加了这一节。

我们的目标是,客户端在点击连接后:

1.产生一个5位数验证码并弹窗显示

2.发送验证码到服务器

3.服务端要求输入验证码,以确定是本人操作。

实现如下:


1. Python验证:

创建一个弹窗类:

import tkinter as tk  # 引入tkinter图形界面包
class MessageBox:
    def __init__(self, code, address):
        self.code = code  # 传入要验证的密码
        self.address = address  # 传入客户端的地址信息
        self.root = tk.Tk()  # 创建主窗口
        self.root.geometry("320x180")  # 设置窗口大小
        # 创建窗口上的元素,并布局
        self.label = tk.Label(self.root, text="请在60秒内输入校验码", font=("Microsoft YaHei", 18))
        self.label.place(x=30, y=30)
        self.entry = tk.Entry(self.root, width=28)
        self.entry.place(x=60, y=100)
        # 绑定事件,响应回车
        self.root.bind("<Return>", self.retrieve_input)
        # 设置最长等待时间
        self.root.after(60000, self.timeout_destroy)
        # 打开主窗口事件循环
        self.root.mainloop()
    def timeout_destroy(self):
        self.root.destroy()  # 关闭窗口
        raise TimeoutError
    def retrieve_input(self, event):
        # self.entry.get()方法可获取entry中输入的字符串
        if self.entry.get() == self.code:
            self.root.destroy()
            # 添加了一个全局变量link_dict,其中存储要建立的连接和状态
            link_dict[self.address] = True  

创建该对象后显示的结果是:

8ce1375e8b2a048e131278c607598d79.png

调整之前写的server部分的结构,包装成一个类:

class Server:
    def __init__(self):
        # 设置一个flag判断这个连接是否通过了验证
        self.checked = False
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.address = ('0.0.0.0', 8000)
        self.server.bind(self.address)
        self.server.listen()
        while True:
            try:
                client, address = self.server.accept()
                threading.Thread(target=self.init_connection, args=(client, address)).start()
                threading.Thread(target=self.io_operation, args=(client,)).start()
            except Exception as e:
                print(e)
                break
        # 关闭socket服务器
        self.server.close()
    # 处理数据
    def parsing_data(self, data):
        # 具体的处理客户端命令的部分,先空着
        return ""
    # I/O操作
    def io_operation(self, current_client):
        while True:
            # 检测是否完成了初始化
            if not self.checked:
                continue
            try:
                # 从客户端接收数据
                data = current_client.recv(1024).decode()
                re_data = "idlen"
                if data:
                    print(data)
                    re_data = self.parsing_data(data)
                # 向客户端发送数据
                current_client.sendall(re_data.encode())
            except ConnectionError:
                print("连接中断")
                break
            except WindowsError:
                print("出现错误")
                break
    # 初始化连接
    def init_connection(self, current_client, current_address):
        # 初始化连接检查
        link_dict[current_address] = False
        # 从客户端接收数据
        data = current_client.recv(1024).decode()
        re_data = "failn"
        if data:
            data_list = data.split()
            # 处理连接标识码 *1
            if data_list[0] == "code":
                def create_msg_box():
                    MessageBox(data_list[1], current_address)
                try:
                    threading.Thread(target=create_msg_box).start()
                except TimeoutError:
                    print("连接超时")
                while True:
                    if link_dict[current_address]:
                        self.checked = True
                        # 返回检验完毕的信息 *2
                        re_data = "checkn"
                        print(current_address, "已连接")
                        break
            else:
                print("非法连接")
        # 向客户端发送数据
        current_client.sendall(re_data.encode())

*1: 约定在客户端采用code xxxxx的字符串格式传入验证码

*2: 约定在服务端检测成功后返回check,否则返回fail或无返回


2. Java验证:

// 连接标志码
int connection_code = (int) (Math.random() * 90000) + 10000;
public boolean CreateSocketConnection() {
    try {
        handler.post(new Runnable() {
            @Override
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setTitle("连接标识码");
                builder.setMessage(connection_code + "");
                builder.setPositiveButton("好的", null);
                builder.setCancelable(false);
                builder.show();
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
    try {
        String host = "192.168.0.104";
        int port = 8000;
        socket = new Socket(host, port);
        is = socket.getInputStream();
        os = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
        bw.write("code " + connection_code); // 发送校验码
        bw.flush();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String msg = br.readLine();
        switch (msg) {
            case "check": {
                System.out.println("连接成功");
                return true;
            }
            case "fail": {
                System.out.println("连接失败");
                return false;
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

先使用AlertDialog类创建一个简单的提示框:

321d49e1f73e2d96281d4170803698d8.png

然后根据之前的约定修改判定条件即可。



版权声明:本文为weixin_42521731原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。