Louie De Janeiru

TcpIp Socket Client 본문

Flutter

TcpIp Socket Client

Louiey 2024. 4. 17. 10:21

dart:io package 를 이용하여 TcpIp Client 기능 구현하였다.

Server IP 와 port number 입력 하고 Connect 버튼 누르면 server 에 연결이 되고 string 을 주고 받을 수 있게 작업되었다.

IP와 port 정보를 입력하지 않으면 default 값인 "127.0.0.1/3333" 이 입력되고 있다.

 

이상한 부분은 ip address 정보를 얻어올때 "get_ip_address" package를 사용했는데 찍히는 ip 정보가 실제 정보와 다르다는 것이다.

Package의 Sample code 대로 했는데 ip 정보가 다르게 읽혀온다.

dart:io 에 있는 API를 이용하여 ip 정보를 확인해 보면 cmd 창에서 읽어온 정보과 같이 읽혀온다.

위 package 도 동작에 문제가 없으니 계속 유지가 되고 있을텐데 왜 정보가 차이가 나는지는 아직 모르겠다.

일단 두 가지 다 적용해서 읽어오고 있다.

 

대부분 sample code 들이 connection 후 message send 하고 socket 을 close하고 있다.

왜 그래야 하는지는 잘 모르겠다.

지금 code는 Message를 보낼때마다 재 연결하지 않도록 connectToServer() 이후에 socket을 close하지 않고 open 한 상태로 사용하고 있다.

이러면 안되나???

 

Received 화면에 색을 입혔는데 영 안이쁘다...

 

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_my_utils/utils/my_utils.dart';
import 'package:get_ip_address/get_ip_address.dart';

class TcpClientSocket extends StatefulWidget {
  const TcpClientSocket({super.key});

  @override
  State<TcpClientSocket> createState() => _TcpSocketState();
}

class _TcpSocketState extends State<TcpClientSocket> {
  final _ipAddress = TextEditingController();
  final _portNo = TextEditingController();
  final _msgSend = TextEditingController();
  List<String> msgList = [];

  bool isConnected = false;

  // var ipAddr = IpAddress(type: RequestType.json);
  String _myIp = "";

  Socket? sock;

  /// get ip address via get_ip_address package
  ///
  /// IP address is different with dart:io
  void _getMyIp() async {
    try {
      /// Initialize Ip Address
      var ipAddress = IpAddress(type: RequestType.json);

      /// Get the IpAddress based on requestType.
      var data = await ipAddress.getIpAddress();
      setState(() {
        _myIp = data.toString();
      });
      utils.log("IP : $_myIp");
    } on IpAddressException catch (exception) {
      /// Handle the exception.
      utils.log(exception.message);
    }
  }

  /// get ip address via dart:io
  Future _printIps() async {
    for (var interface in await NetworkInterface.list()) {
      utils.log('== Interface: ${interface.name} ==');
      for (var addr in interface.addresses) {
        utils.log(
            '${addr.address} ${addr.host} ${addr.isLoopback} ${addr.rawAddress} ${addr.type.name}');
      }
    }
  }

  /// get server ip address string
  String _getServerIp() {
    if (_ipAddress.text.isEmpty) {
      return "127.0.0.1";
    } else {
      return _ipAddress.text;
    }
  }

  /// get port number int
  int _getPortNo() {
    if (_portNo.text.isEmpty) {
      return 3333;
    } else {
      return (int.parse(_portNo.text));
    }
  }

  @override
  void initState() {
    super.initState();
    _getMyIp();
    _printIps();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Tcp Client Socket"),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(10),
        // scrollDirection: Axis.horizontal,
        child: Column(
          children: [
            _menuGetServerIpPortNo(),
            const Divider(),
            _menuMessageSend(),
            const Divider(),
            _menuReceivedMessage(),
            const Divider(),
          ],
        ),
      ),
    );
  }

  /// menu to get server ip and port number
  _menuGetServerIpPortNo() {
    return Row(
      children: [
        const SizedBox(width: 10),
        const Text("Server IP"),
        const SizedBox(width: 10),
        Expanded(
          child: SizedBox(
            width: 200,
            child: TextField(
              // initialValue: "127.0.0.1",
              controller: _ipAddress,
              decoration: InputDecoration(
                  labelText: "input server ip",
                  hintText: "127.0.0.1",
                  // helperText: "127.0.0.1",
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10))),
            ),
          ),
        ),
        const SizedBox(width: 10),
        Expanded(
          child: SizedBox(
            width: 100,
            child: TextField(
              controller: _portNo,
              decoration: InputDecoration(
                  labelText: "Port No",
                  hintText: "3333",
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10))),
            ),
          ),
        ),
        const SizedBox(width: 10),
        Expanded(
          child: ElevatedButton(
            onPressed: () async {
              try {
                if (isConnected == false) {
                  connectToServer(_getServerIp(), _getPortNo());
                } else {
                  disconnectServer();
                }
              } catch (e) {
                utils.log(e.toString());
              }
            },
            child: Text(isConnected ? "Disconnect" : "Connect"),
          ),
        ),
      ],
    );
  }

  /// menu for tx message send
  _menuMessageSend() {
    return Card(
      child: ListTile(
        leading: IconButton(
          onPressed: () {
            try {
              setState(() {
                msgList.clear();
              });
            } catch (e) {
              utils.log(e.toString());
            }
          },
          icon: const Icon(Icons.cleaning_services),
        ),
        title: TextField(
          controller: _msgSend,
        ),
        trailing: IconButton(
          onPressed: () {
            try {
              sendMessage(_msgSend.text);
            } catch (e) {
              utils.log(e.toString());
            }
          },
          icon: const Icon(Icons.send),
        ),
      ),
    );
  }

  /// menu to display received message from server
  _menuReceivedMessage() {
    return SizedBox(
      height: 200,
      child: Card(
        color: Colors.yellow[200],
        child: SingleChildScrollView(
          reverse: true,
          child: ListView.builder(
            shrinkWrap: true,
            // reverse: true,
            itemCount: msgList.length,
            itemBuilder: (context, int idx) {
              return Container(
                margin: const EdgeInsets.symmetric(vertical: 2, horizontal: 2),
                padding:
                    const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
                decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(3),
                    color: msgList[idx].contains("tx")
                        ? Colors.amber[100]
                        : Colors.green[100]),
                child: Text(msgList[idx]),
              );
            },
          ),
        ),
      ),
    );
  }

  /// send string message to server
  sendMessage(String msg) async {
    try {
      if (sock != null) {
        utils.log("Trying to send \"$msg\"");
        // Send data to the server
        sock!.writeln(msg);
        setState(() {
          msgList.add("tx => $msg");
        });
      } else {
        utils.log("please connect to server before try to send message");
      }
    } catch (e) {
      utils.log('Error: $e');
    }
  }

  /// connect to server
  connectToServer(String serverIp, int serverPort) async {
    try {
      sock = await Socket.connect(serverIp, serverPort,
          timeout: const Duration(seconds: 15));

      setState(() {
        isConnected = true;
      });
      // Listen for data from the server
      utils.log("Listening...");
      sock!.listen(
        (data) {
          utils.log('Received from server: ${String.fromCharCodes(data)}');
          setState(() {
            msgList.add("rx => ${String.fromCharCodes(data)}");
          });
        },
        onDone: () {
          utils.log('Server disconnected.');
          sock!.destroy();
        },
        onError: (error) {
          utils.log('Error: $error');
          sock!.destroy();
          isConnected = false;
        },
      );

      // Close the socket when you're done
      // if (sock != null) {
      //   sock!.close();
      // }
    } catch (e) {
      utils.log('Error: $e');
    }
  }

  /// disconnect from server
  disconnectServer() {
    try {
      // Close the socket when you're done
      if (sock != null) {
        sock!.close();
        utils.log("Socket closed");
        setState(() {
          isConnected = false;
        });
      }
    } catch (e) {
      utils.log('Error: $e');
    }
  }
}

 

 

SerialPortMon을 server로 설정한 후 접속하여 message를 보내고 받았음

 

 

https://github.com/louiey-dev/flutter_my_utils/blob/main/lib/tcpip/tcp_socket_client.dart

 

flutter_my_utils/lib/tcpip/tcp_socket_client.dart at main · louiey-dev/flutter_my_utils

Flutter sample code. Contribute to louiey-dev/flutter_my_utils development by creating an account on GitHub.

github.com

 

'Flutter' 카테고리의 다른 글

showDialog/AlertDialog  (0) 2024.05.07
TcpIp Socket Server  (0) 2024.04.17
Button 만들기  (0) 2024.04.15
ListView.builder  (0) 2024.04.15
Debug banner remove in Flutter  (0) 2024.04.15