Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
H
hemei
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
潘栩锋
hemei
Commits
b92d8fb2
Commit
b92d8fb2
authored
Jan 20, 2019
by
潘栩锋
🚴
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
添加 Modbus.ServerTCP.cs 的线程版本
parent
80afe529
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
635 additions
and
1 deletion
+635
-1
FLY.ModbusMapper.csproj
...FLY.ModbusMapper/FLY.ModbusMapper/FLY.ModbusMapper.csproj
+2
-0
ClientTCP.cs
...FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ClientTCP.cs
+1
-1
IModbusClient.cs
...ModbusMapper/FLY.ModbusMapper/WithThread/IModbusClient.cs
+26
-0
IModbusServer.cs
...ModbusMapper/FLY.ModbusMapper/WithThread/IModbusServer.cs
+48
-0
ServerTCP.cs
...FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ServerTCP.cs
+558
-0
No files found.
Project.FLY.ModbusMapper/FLY.ModbusMapper/FLY.ModbusMapper.csproj
View file @
b92d8fb2
...
...
@@ -61,7 +61,9 @@
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"WithThread\ClientTCP.cs"
/>
<Compile
Include=
"WithThread\IModbusClient.cs"
/>
<Compile
Include=
"WithThread\IModbusServer.cs"
/>
<Compile
Include=
"WithThread\ModbusMapper_Client.cs"
/>
<Compile
Include=
"WithThread\ServerTCP.cs"
/>
</ItemGroup>
<ItemGroup>
<ProjectReference
Include=
"..\..\Project.FLY.FObjSys\FObjSys\FObjBase.csproj"
>
...
...
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ClientTCP.cs
View file @
b92d8fb2
...
...
@@ -21,7 +21,7 @@ namespace FLY.Modbus.WithThread
/// </summary>
public
TimeSpan
Timeout
{
get
;
set
;
}
=
TimeSpan
.
FromSeconds
(
2
);
/// <summary>
/// socket 错误信息
,带时间
/// socket 错误信息
/// </summary>
public
string
ErrMsg
{
get
;
set
;
}
...
...
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/IModbusClient.cs
View file @
b92d8fb2
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
namespace
FLY.Modbus.WithThread
...
...
@@ -16,6 +17,31 @@ namespace FLY.Modbus.WithThread
/// </summary>
TimeSpan
Timeout
{
get
;
set
;
}
/// <summary>
/// socket 错误信息
/// </summary>
string
ErrMsg
{
get
;
set
;
}
/// <summary>
/// 连接成功
/// </summary>
bool
IsConnected
{
get
;
set
;
}
/// <summary>
/// 远端地址
/// </summary>
IPEndPoint
RemoteEP
{
get
;
set
;
}
/// <summary>
/// 建立连接
/// </summary>
bool
Connect
();
/// <summary>
/// 停止
/// </summary>
void
Close
();
/// <summary>
/// 读多个 COIL
/// </summary>
...
...
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/IModbusServer.cs
0 → 100644
View file @
b92d8fb2
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
namespace
FLY.Modbus.WithThread
{
public
interface
IModbusServer
{
/// <summary>
/// 通信超时, client 长时间连接上,但不通讯,会被断开
/// </summary>
TimeSpan
Timeout
{
get
;
set
;
}
/// <summary>
/// 本地地址
/// </summary>
IPEndPoint
LocalEP
{
get
;
set
;
}
/// <summary>
/// 当前连接数
/// </summary>
int
ConnectedCnt
{
get
;
}
/// <summary>
/// 工作中
/// </summary>
bool
IsRunning
{
get
;
set
;
}
/// <summary>
/// socket 错误信息
/// </summary>
string
ErrMsg
{
get
;
set
;
}
GetValueHander
GetValue
{
get
;
}
SetValueHander
SetValue
{
get
;
}
void
Start
();
void
Stop
();
}
public
delegate
void
GetValueHander
(
int
addr
,
object
values
);
public
delegate
void
SetValueHander
(
int
addr
,
object
values
);
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ServerTCP.cs
0 → 100644
View file @
b92d8fb2
using
System
;
using
System.Collections.Generic
;
using
System.ComponentModel
;
using
System.Linq
;
using
System.Net
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Threading
;
using
System.Threading.Tasks
;
namespace
FLY.Modbus.WithThread
{
public
class
ServerTCP
:
IModbusServer
,
INotifyPropertyChanged
{
/// 通信超时, client 长时间连接上,但不通讯,会被断开
/// </summary>
public
TimeSpan
Timeout
{
get
;
set
;
}
=
TimeSpan
.
FromMinutes
(
1
);
/// <summary>
/// 本地地址
/// </summary>
public
IPEndPoint
LocalEP
{
get
;
set
;
}
/// <summary>
/// 当前连接数
/// </summary>
public
int
ConnectedCnt
{
get
;
private
set
;
}
/// <summary>
/// 工作中
/// </summary>
public
bool
IsRunning
{
get
;
set
;
}
/// <summary>
/// socket 错误信息
/// </summary>
public
string
ErrMsg
{
get
;
set
;
}
public
GetValueHander
GetValue
{
get
;
private
set
;
}
public
SetValueHander
SetValue
{
get
;
private
set
;
}
Socket
listen_socket
;
List
<
Client
>
clients
=
new
List
<
Client
>();
CancellationTokenSource
cts
;
public
ServerTCP
(
IPEndPoint
ep
,
GetValueHander
getValue
,
SetValueHander
setValue
)
{
LocalEP
=
ep
;
GetValue
=
getValue
;
SetValue
=
setValue
;
}
public
void
Start
()
{
lock
(
this
)
{
if
(
IsRunning
)
return
;
IsRunning
=
true
;
cts
=
new
CancellationTokenSource
();
Task
.
Factory
.
StartNew
(
OnPoll_listen
,
cts
.
Token
);
}
}
public
void
Stop
()
{
lock
(
this
)
{
if
(!
IsRunning
)
return
;
cts
.
Cancel
();
listen_socket
.
Close
();
while
(
true
)
{
Client
client
;
lock
(
clients
)
{
if
(
clients
.
Count
()
==
0
)
break
;
client
=
clients
.
First
();
clients
.
Remove
(
client
);
}
client
.
Close
();
}
}
}
void
OnPoll_listen
()
{
listen_socket
=
new
Socket
(
AddressFamily
.
InterNetwork
,
SocketType
.
Stream
,
ProtocolType
.
Tcp
);
listen_socket
.
Bind
(
LocalEP
);
listen_socket
.
Listen
(
5
);
while
(
true
)
{
if
(
cts
.
IsCancellationRequested
)
goto
_end
;
try
{
Socket
socket
=
listen_socket
.
Accept
();
Client
client
=
new
Client
(
socket
,
this
);
client
.
Closed
+=
Client_Closed
;
client
.
Start
();
lock
(
client
)
{
clients
.
Add
(
client
);
ConnectedCnt
=
clients
.
Count
();
}
}
catch
(
Exception
e
)
{
goto
_end
;
}
}
_end
:
IsRunning
=
false
;
}
private
void
Client_Closed
(
object
obj
)
{
lock
(
clients
)
{
clients
.
Remove
(
obj
as
Client
);
}
}
public
delegate
void
ClosedHandler
(
object
obj
);
class
Client
{
public
Socket
socket
;
public
CancellationTokenSource
cts
;
ServerTCP
server
;
public
Client
(
Socket
socket
,
ServerTCP
server
)
{
this
.
socket
=
socket
;
this
.
server
=
server
;
}
public
void
Start
()
{
cts
=
new
CancellationTokenSource
();
Task
.
Factory
.
StartNew
(
OnPoll_client
,
cts
.
Token
);
}
bool
PullRequest
(
out
Pack_Proto
request
)
{
//格式——————————————
//MBAP
//域 长度 描述
//事务标识符 2byte MODBUS请求/响应的识别码
//协议标识符 2byte 0=MODBUS协议
//——长度— 2byte 以下字节的数量
//单元标识符 1byte 串行链路或其它总线过来的识别码
//PDU
//功能码—— 1byte
//数据 nbyte
byte
[]
recvBytes
=
new
byte
[
socket
.
ReceiveBufferSize
];
socket
.
ReceiveTimeout
=
(
int
)
server
.
Timeout
.
TotalMilliseconds
;
request
=
new
Pack_Proto
();
int
offset
=
0
;
//读取数据
while
(
true
)
{
int
size
=
recvBytes
.
Length
-
offset
;
if
(
size
<=
0
)
{
//异常
server
.
ErrMsg
=
"client error: rec to many!!!"
;
return
false
;
}
int
bytes
=
0
;
try
{
bytes
=
socket
.
Receive
(
recvBytes
,
offset
,
size
,
SocketFlags
.
None
);
//从客户端接受信息,可能会分了多次接收
}
catch
(
SocketException
e
)
{
//异常
server
.
ErrMsg
=
$"client error:
{
e
.
Message
}
"
;
return
false
;
}
if
(
bytes
==
0
)
{
//超时,或已经断开连接
server
.
ErrMsg
=
"client error: TimeOut"
;
return
false
;
}
//肯定只回复一条,只需要翻译一条
if
(!
request
.
TryParse
(
recvBytes
,
0
,
bytes
,
out
int
rlen
))
{
//处理失败,数据不够,继续接收
offset
=
bytes
;
}
else
{
//完成!!!!
return
true
;
}
}
}
bool
PushReponse
(
Pack_Proto
reponse
)
{
try
{
socket
.
Send
(
reponse
.
ToBytes
());
}
catch
(
Exception
e
)
{
server
.
ErrMsg
=
e
.
Message
;
return
false
;
}
return
true
;
}
void
OnPoll_client
()
{
while
(
true
)
{
if
(
cts
.
IsCancellationRequested
)
goto
_error
;
bool
ret
=
PullRequest
(
out
Pack_Proto
request
);
if
(!
ret
)
goto
_error
;
ParsePacket
(
request
,
out
Pack_Proto
reponse
);
ret
=
PushReponse
(
reponse
);
if
(!
ret
)
goto
_error
;
}
_error
:
Close
();
}
public
void
Close
()
{
cts
.
Cancel
();
socket
.
Close
();
Closed
?.
Invoke
(
this
);
}
public
event
ClosedHandler
Closed
;
void
ParsePacket
(
Pack_Proto
request
,
out
Pack_Proto
reponse
)
{
switch
(
request
.
func
)
{
case
0x03
:
// read holding registers
Do_03
(
request
,
out
reponse
);
break
;
case
0x01
:
// read coils
Do_01
(
request
,
out
reponse
);
break
;
case
0x10
:
// write multiple registers
Do_10
(
request
,
out
reponse
);
break
;
case
0x06
:
// Write single register
Do_06
(
request
,
out
reponse
);
break
;
case
0x05
:
// Write single coil
Do_05
(
request
,
out
reponse
);
break
;
case
0x0f
:
// Write mutiple coils
Do_0f
(
request
,
out
reponse
);
break
;
default
:
Do_Exception
(
request
,
0x01
,
out
reponse
);
break
;
}
}
#
region
处理
/// <summary>
/// 异常处理
/// </summary>
void
Do_Exception
(
Pack_Proto
request
,
byte
e_code
,
out
Pack_Proto
reponse
)
{
byte
func
=
request
.
func
;
Misc
.
MyBase
.
SIGNBIT
(
ref
func
,
7
);
reponse
=
new
Pack_Proto
()
{
tranid
=
request
.
tranid
,
unitid
=
request
.
unitid
,
func
=
func
,
buf
=
new
byte
[
1
]
{
e_code
}
};
}
#
region
功能
/// <summary>
/// 读多个 COIL
/// </summary>
void
Do_01
(
Pack_Proto
request
,
out
Pack_Proto
reponse
)
{
int
index
=
0
;
//开始地址
UInt16
start
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
//数量
UInt16
num
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
if
((
num
<
0x01
)
||
(
num
>
0x07D0
))
{
Do_Exception
(
request
,
0x03
,
out
reponse
);
return
;
}
bool
[]
value
=
new
bool
[
num
];
server
.
GetValue
(
start
,
value
);
List
<
byte
>
data
=
new
List
<
byte
>();
data
.
Add
((
byte
)(
Math
.
Ceiling
(
num
/
8.0
)));
//返回的字节数
for
(
int
i
=
0
,
j
=
0
;
i
<
num
;
i
++)
{
if
(
j
==
0
)
data
.
Add
(
0
);
if
(
value
[
i
])
{
data
[
data
.
Count
-
1
]
=
(
byte
)(
data
[
data
.
Count
-
1
]
|
Misc
.
MyBase
.
BIT
(
i
%
8
));
}
j
++;
if
(
j
==
8
)
{
j
=
0
;
}
}
reponse
=
new
Pack_Proto
()
{
tranid
=
request
.
tranid
,
unitid
=
request
.
unitid
,
func
=
request
.
func
,
buf
=
data
.
ToArray
()
};
}
/// <summary>
/// 读多个REG
/// </summary>
/// <param name="ptran"></param>
void
Do_03
(
Pack_Proto
request
,
out
Pack_Proto
reponse
)
{
int
index
=
0
;
//开始地址
UInt16
start
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
//数量
UInt16
num
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
if
((
num
<
0x01
)
||
(
num
>
0x007D
))
{
Do_Exception
(
request
,
0x03
,
out
reponse
);
return
;
}
UInt16
[]
value
=
new
UInt16
[
num
];
server
.
GetValue
(
start
,
value
);
List
<
byte
>
data
=
new
List
<
byte
>();
data
.
Add
((
byte
)(
num
*
2
));
for
(
int
i
=
0
;
i
<
num
;
i
++)
{
data
.
AddRange
(
value
[
i
].
GetBytes_Big_endian
());
}
reponse
=
new
Pack_Proto
()
{
tranid
=
request
.
tranid
,
unitid
=
request
.
unitid
,
func
=
request
.
func
,
buf
=
data
.
ToArray
()
};
}
/// <summary>
/// 写单个coil
/// </summary>
void
Do_05
(
Pack_Proto
request
,
out
Pack_Proto
reponse
)
{
int
index
=
0
;
//开始地址
UInt16
start
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
//数量
UInt16
value
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
if
((
value
!=
0xff00
)
&&
(
value
!=
0x0000
))
{
Do_Exception
(
request
,
0x03
,
out
reponse
);
return
;
}
bool
[]
v
=
new
bool
[
1
];
if
(
value
==
0xff00
)
v
[
0
]
=
true
;
else
v
[
0
]
=
false
;
server
.
SetValue
(
start
,
v
);
reponse
=
request
;
}
/// <summary>
/// 写单个REG
/// </summary>
void
Do_06
(
Pack_Proto
request
,
out
Pack_Proto
reponse
)
{
int
index
=
0
;
//开始地址
UInt16
start
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
//数量
UInt16
value
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
UInt16
[]
v
=
new
UInt16
[
1
];
v
[
0
]
=
value
;
server
.
SetValue
(
start
,
v
);
reponse
=
request
;
}
/// <summary>
/// 写多个coil
/// </summary>
/// <param name="ptran"></param>
void
Do_0f
(
Pack_Proto
request
,
out
Pack_Proto
reponse
)
{
int
index
=
0
;
//开始地址
UInt16
start
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
//数量
UInt16
num
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
if
((
num
<
0x01
)
||
(
num
>
0x007D
))
{
Do_Exception
(
request
,
0x03
,
out
reponse
);
return
;
}
byte
byte_cnt
=
request
.
buf
[
index
];
index
++;
bool
[]
v
=
new
bool
[
num
];
for
(
int
i
=
0
,
j
=
0
;
i
<
num
;
i
++)
{
if
(
Misc
.
MyBase
.
CHECKBIT
(
request
.
buf
[
index
],
j
))
v
[
i
]
=
true
;
else
v
[
i
]
=
false
;
j
++;
if
(
j
==
8
)
{
j
=
0
;
index
++;
}
}
server
.
SetValue
(
start
,
v
);
List
<
byte
>
data
=
new
List
<
byte
>();
data
.
AddRange
(
start
.
GetBytes_Big_endian
());
data
.
AddRange
(
num
.
GetBytes_Big_endian
());
reponse
=
new
Pack_Proto
()
{
tranid
=
request
.
tranid
,
unitid
=
request
.
unitid
,
func
=
request
.
func
,
buf
=
data
.
ToArray
()
};
}
/// <summary>
/// 写多个REG
/// </summary>
/// <param name="ptran"></param>
void
Do_10
(
Pack_Proto
request
,
out
Pack_Proto
reponse
)
{
int
index
=
0
;
//开始地址
UInt16
start
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
//数量
UInt16
num
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
byte
byte_cnt
=
request
.
buf
[
index
];
index
++;
if
((
num
<
0x01
)
||
(
num
>
0x007D
))
{
Do_Exception
(
request
,
0x03
,
out
reponse
);
return
;
}
UInt16
[]
v
=
new
UInt16
[
num
];
for
(
int
i
=
0
;
i
<
num
;
i
++)
{
v
[
i
]
=
COMMON
.
ToUInt16_Big_endian
(
request
.
buf
,
index
);
index
+=
2
;
}
server
.
SetValue
(
start
,
v
);
List
<
byte
>
data
=
new
List
<
byte
>();
data
.
AddRange
(
start
.
GetBytes_Big_endian
());
data
.
AddRange
(
num
.
GetBytes_Big_endian
());
reponse
=
new
Pack_Proto
()
{
tranid
=
request
.
tranid
,
unitid
=
request
.
unitid
,
func
=
request
.
func
,
buf
=
data
.
ToArray
()
};
}
#
endregion
#
endregion
}
public
event
PropertyChangedEventHandler
PropertyChanged
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment