How to create modbus master/server tcp in flutter? - flutter

I want to create desktop app to communicate with PLC using modbus. I found modbus package, but I can not implement modbus server. There is only client implementation. I've read modbus source code and found that modbus client was created using Socket from dart:io. Can we create modbus server using ServerSocket?. I've tried to create tcp server using ServerSocket and modbus client then connect it. Modbus client can connect to tcp server and tcp server will receive Uint8List data if modbus client do writeSingleRegister or readHoldingRegisters.
Server socket will receive this data if modbus client do write single register with address 4 and value 5
[0,1,0,0,0,6,10,6,0,4,0,5]
1 is sequence
The second 6 => always 6 for write single register
4 is address
5 is value
Server socket wil receive this data if modbus client do read single register with address 4 and amount 5
[0,1,0,0,0,6,10,3,0,4,0,5]
1 is sequence
3 => always 3 for read single register
4 is address
5 is amount
Create server
void createServer(){
ServerSocket.bind("127.0.0.1", 4000)
.then((server) {
server.listen((socket) {
socket.listen((event) {
print(event);
// how to send data result to client?
// socket.write() and socket.add() give errors
socket.write(Uint16List.view(event.buffer,0,1));
// error => Unhandled Exception: RangeError (byteOffset): Invalid value: Not in inclusive range 0..3: 4
});
});
});
}
Future<void>read(modbus.ModbusClient client,int address, int amount)async{
Uint16List data = await client.readHoldingRegisters(address, amount);
print(data);
}
Problem
How to send data to modbus client if client do readHoldingRegisters
using ServerSocket?

Related

Flutter: Sending un ascii characters to server using socket.io

Im using flutter socket.io to connect to our server. The server doesnt use http protocol etc, straight connect, read and write, so I cant use WebSockets. I have the following:
Socket socket;
Uint8List BTBuffer = new Uint8List(10); //a buffer to hold data
Socket.connect("192.168.68.120", 21000);
.then((Socket sock) {
socket = sock;
socket.listen(dataHandler); //read data from server (data handler reads the data from server)
BTBuffer[0]=1;BTBuffer[1]=2;
socket.write(BTBuffer);
socket.destroy();
});
The above works, but it sends the values as strings and not decimal values. How can I send the values 1 and 2 for example in decimal? I was assuming there would be a write command pointing to a buffer and number of bytes to send.
Many Thanks
Scott

I can not sent short messages by TCP protocol

I have a trouble to tune TCP client-server communication.
My current project has a client, running on PC (C#) and a server,
running on embedded Linux 4.1.22-ltsi.
Them use UDP communication to exchanging data.
The client and server work in blocking mode and
send short messages one to 2nd
(16, 60, 200 bytes etc.) that include either command or set of parameters.
The messages do note include any header with message length because
UDP is message oriented protocol. Its recvfrom() API returns number of received bytes.
For my server's program structure is important to get and process entire alone message.
The problem is raised when I try to implement TCP communication type instead of UDP.
The server's receive buffer (recv() TCP API) is 2048 bytes:
#define UDP_RX_BUF_SIZE 2048
numbytes = recv(fd_connect, rx_buffer, UDP_RX_BUF_SIZE, MSG_WAITALL/*BLOCKING_MODE*/);
So, the recv() API returns from waiting when rx_buffer is full, i.e after it receives
2048 bytes. It breaks all program approach. In other words, when client send 16 bytes command
to server and waits an answer from it, server's recv() keeps the message
"in stomach", until it will receive 2048 bytes.
I tried to fix it as below, without success:
On client side (C#) I set the socket parameter theSocket.NoDelay.
When I checked this on the sniffer I saw that client sends messages "as I want",
with requested length.
On server side I set TCP_NODELAY socket option to 1
int optval= 1;
setsockopt(fd,IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval);
On server side (Linux) I checked socket options SO_SNDLOWAT/SO_RCVLOWAT and they are 1 byte each one.
Please see the attached sniffer's log picture. 10.0.0.10 is a client. 10.0.0.106 is a server. It is seen, that client activates PSH flag (push), informing the server side to move the incoming data to application immediately and do not fill a buffer.
Additional question: what is SSH encrypted packets that runs between the sides. I suppose that it is my Eclipse debugger on PC (running server application through the same Ethernet connection) sends them. Am I right?
So, my problem is how to cause `recv() API to return each short message (16, 60, 200 bytes etc.) instead of accumulating them until receiving buffer fills.
TCP is connection oriented and it also maintains the order in which packets are sent and received.
Having said that, in TCP client, you will receive the stream of bytes and not the individual udp message as in UDP. So you will need to send the packet length and marker as the initial bytes.
So client can first find the packet length and then read data till packet length is reached and then expect new packet length.
You can also check for library like netty, zmq to do this extra work

TCP Socket connection- Unable to read data sent from external client even after serializing through ByteArrayLengthHeaderSerializer

I have implemented TCP socket server which accepts incoming XML messages from client. I could send messages through telnet.
But when I am trying to establish connection and send message through python script, I was getting IOException:CRLF not found before max message length: 2048.So I have added ByteArrayLengthHeaderSerializer to serialize and deserialize, but now I am getting below error.
IOException:Message length 1014132591 exceeds max message length: 2048
Though I am increasing the max message length I am getting IOException:Stream closed after 46 of 1014132591
Could someone let me know how to fix the issue.
final AbstractServerConnectionFactory crLfServer = context.getBean(AbstractServerConnectionFactory.class);
ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer();
serializer.setMaxMessageSize(1000 * 1024);
crLfServer.setSerializer(serializer);
crLfServer.setDeserializer(serializer);
I have implemented using Spring Integration.Below is the snippet for my inbound adapter
#Bean
public TcpReceivingChannelAdapter inboundAdapter(AbstractServerConnectionFactory connectionFactory) {
System.out.println("Creating inbound adapter");
TcpReceivingChannelAdapter inbound = new TcpReceivingChannelAdapter();
inbound.setConnectionFactory(connectionFactory);
//inbound.
inbound.setOutputChannel(fromTcp());
return inbound;
}
I think might be better to send exactly that CRLF in your script after the message. That will be exactly delimiter for the messages to deserialize. This is one what is used by the mentioned Telnet. However you need to come back to the default deserializer in the connection factory configuration.

How to use publish data over TCP socket instead of UDP

I have been trying to to use pubnub in order to sent data stream through peers. What is happening though is that the message size on the one side is different from the one the other, though the number of messages sent and received are the same.What i have in mind is that by somehow part of the packets are lost
pubnub.publish({
channel: 'my_channel',
'message' : {
'packet': array_of_packets[counter_array_of_packets],
'which_packet_is': counter_array_of_packets,
'payload_size': calculate_payload_size('my_channel'array_of_packets[counter_array_of_packets])
}
callback : function(m){console.log(m)}
});
pubnub.subscribe({
channel: 'my_channel',
message: function(m){wait_(m)},
uuid: 'Mitsos',
error: function (error) {
// Handle error here
console.log(JSON.stringify(error));
}
});
The function used to calculate the size is:
function calculate_payload_size( channel, message ) {
return encodeURIComponent(
channel + JSON.stringify(message)
).length + 100;
}
So how can i use the above two functions publish and subscribe in a way that the TCP (reliable transmitting) is used?
(if this can be of any help here is implemented a working example of pubnub - index.html where packets reach the right way the other side, though i can't seem to find if he uses tcp anywhere link)
All PubNub client libraries communicate over a TCP socket connection only.
If you are using PubNub JavaScript, Java or Objective-C SDK, then the SDK will take care of Keeping the TCP Socket Connection open for you automatically after you have subscribed to a data channel. This guide on http-streaming-over-tcp-with-telnet-example will provide an easy way to use Telnet as an example of Streaming your JSON message payloads over TCP socket.
You can keep a TCP Socket active and alive forever with PubNub's unlimited TTL Socket Session Policy by writing an initial data payload over the socket. After you've established the TCP connection, send an initial payload. Watch this video on Keeping a TCP Socket Connection Open on your first Network Call which walks you through the steps of how to keep a TCP socket connection open.

Socket listen when using Single Client

I wrote a server code to run on my embedded platform...it listens to wifi clients and I have made provision to accept only one client connection at a time.
so I do,
sfd = socket(AF_INET, SOCK_STREAM, 0);
ret=bind(sfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
ret = listen(sfd,5);
while(1)
{
new_fd = accept(sfd,(struct sockaddr*)&client_addr,&len);
....
close(new_fd);
}
So in this case what I observe that only one client can send data...which is expected
But, Another client can connect to the socket simultaneouly...although the data from 2nd client is not processed.
So is this because of the listen(5) backlog parameter. So that I can simultaneously connect to 5 connections although I may not process them.
Please help me clarify.