Flutter with Sockets
Web Socket is an advanced technology used to create a connection between a client and a server and to be a real-time communication bridge between them.
It is constantly used in many areas such as online games, chat applications, IoT applications.
Socket.io is a library built on web socket features but offers more features to users.
Basically, socket.io is a room structure where users can communicate via a channel.
As a result, web socket and socket.io are an ideal structure that facilitates real-time communication in web applications and provides instant data flow between clients and the server
Client Side
On the mobile application side, we first add our socket_io_client and web_socket_channel libraries to our pubspec.yaml file.
dependencies:
flutter:
sdk: flutter
socket_io_client:
web_socket_channel:
Web Socket Classic
First, let’s start with the Classic Web socket and create a channel variable. We will provide all connections and communications through this variable. Then, let’s create a Connect button and make the connection through this button.
WebSocketChannel? channel;
IconButton(onPressed: (){
setState(() {
channel = WebSocketChannel.connect(Uri.parse('ws://192.168.100.98:8080'));
});
}, icon: Icon(FontAwesomeIcons.plug,color:Colors.green)),
For the listening structure, we can capture messages by listening to the stream in the channel with StreamBuilder over the channel we have created a connection to.
StreamBuilder(
stream: channel!.stream,
builder: (context, snapshot) {
if(snapshot.data != null)
{
print(snapshot.data);
buffer.add(Message(snapshot.data,0));
}
return
Expanded(
child: Container(
color: Colors.grey.shade200,
child: ListView.builder(
itemCount: buffer.length,
itemBuilder: (context,index)
{
return BubbleSpecialThree(
color: buffer[index].sender==1?Colors.white70:Colors.lightBlueAccent,
text: buffer[index].text!,
isSender: buffer[index].sender==1?true:false,
textStyle: TextStyle(color: Colors.black),
);
},
),
),
);
}
),
I also used the chat_bubbles library to create visuals.
When sending messages via web socket, we use the sink.add(“value”) function over the channel we created.
TextField(
controller: controller,
decoration: InputDecoration(
suffixIcon: InkWell(
onTap: ()async{
String text = controller.text;
channel!.sink.add(text);
setState(() {
buffer.add(Message(text,1));
controller.text = "";
});
},
child: Icon(Icons.send),
)
),
)
To close the connection on the channel, we use the sink.close() function again.
channel!.sink.close();
Socket.Io
First, we add our library.
import 'package:socket_io_client/socket_io_client.dart' as IO;
Then we define the socket variable.
IO.Socket socket = IO.io('ws://192.168.100.71:7000/',IO.OptionBuilder().setTransports(['websocket']).build(),);
Let’s add our StreamSocket class, which we will use to send data via socket and receive incoming data via stream.
class StreamSocket{
final _socketResponse= StreamController<String>();
void Function(String) get addResponse => _socketResponse.sink.add;
Stream<String> get getResponse => _socketResponse.stream;
void dispose(){
_socketResponse.close();
}
}
Let’s call our variable from the StreamSocket class.
StreamSocket streamSocket =StreamSocket();
In initState, we call our state functions that we will listen to, such as the error status and connection status of our socket.
socket.onError((data) => print("Error --> $data"));
socket.onConnecting((data) => print("Connecting --> $data"));
socket.onConnectError((data) => print("Connect Error --> $data"));
socket.onConnect((data) => print("Connect --> $data"));
Socket.io works with channel logic. In order to listen to the data coming from the server side and send data, we need to connect to the relevant channel.
We open our listening channel in InitState. We trigger the addResponse function of our streamSocket variable every time data arrives.
socket.on("tm:tasks", (data){
streamSocket.addResponse;
setState(() {
buffer.add(Message("TM --> $data",0));
});
});
Finally, we open our socket and establish a connection.
socket.open();
socket.connect();
Now, let’s edit the stream channel that comes with streamsocket.getresponse with streambuilder and transfer it to the user.
StreamBuilder(stream: streamSocket.getResponse, builder: (context,snapshot){
return Expanded(
child: Container(
color: Colors.grey.shade200,
child: ListView.builder(
itemCount: buffer.length,
itemBuilder: (context,index)
{
return BubbleSpecialThree(
color: buffer[index].sender==1?Colors.white70:Colors.lightBlueAccent,
text: buffer[index].text!,
isSender: buffer[index].sender==1?true:false,
textStyle: TextStyle(color: Colors.black),
);
},
),
),
);
}),
Let’s add our data sending operations that we will use in TextField. In the same way, we emit the data we will send to the relevant channel of the socket.
onTap: ()async{
String text = controller1.text;
socket.emit("ch:chat",controller1.text);
setState(() {
buffer.add(Message("TM --> "+text,1));
controller1.text = "";
});
},
Finally, we call the socket disconnect function to terminate the connection.
socket.disconnect();
For the Web Socket Classic Server side, I used the programs I found on the Microsoft Store and it worked. For Socket.Io, I set up a simple socket.io server via node.js, but I did not feel the need to share it because it was very short.
Especially Socket.Io allows me to carry out my communication work quickly thanks to the communication channels that I use many times in my applications.