作者:sjm2003
转自:http://bbs.csdn.net/topics/240024868
Socket通讯:
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
public
class
XmlSocket
{
//异步socket诊听
// Incoming data from client.从客户端传来的数据
public
static
string
data =
null
;
// Thread signal.线程 用一个指示是否将初始状态设置为终止的布尔值初始化 ManualResetEvent 类的新实例。
public
static
ManualResetEvent allDone =
new
ManualResetEvent(
false
);
//static void Main(string[] args)
//{
// StartListening();
//}
public
static
void
StartListening()
{
// Data buffer for incoming data. 传入数据缓冲
byte
[] bytes =
new
Byte[1024];
// Establish the local endpoint for the socket. 建立本地端口
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPAddress ipAddress;
String ipString = ConfigurationManager.AppSettings.Get(
"SocketIP"
);
if
(ipString==
null
|| ipString ==String.Empty)
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
ipAddress = ipHostInfo.AddressList[0];
}
else
{
ipAddress = IPAddress.Parse(ipString);
}
int
port;
String portString = ConfigurationManager.AppSettings.Get(
"SocketPort"
);
if
(portString==
null
|| portString==String.Empty)
{
port = 11001;
}
else
{
port =
int
.Parse(portString);
}
IPEndPoint localEndPoint =
new
IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket listener =
new
Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.绑定端口和数据
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while
(
true
)
{
// Set the event to nonsignaled state.设置无信号状态的事件
allDone.Reset();
// Start an asynchronous socket to listen for connections.重新 启动异步连接
listener.BeginAccept(
new
AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.等待连接创建后继续
allDone.WaitOne();
}
}
catch
(Exception e)
{
//
}
}
public
static
void
AcceptCallback(IAsyncResult ar)
{
try
{
// Signal the main thread to continue.接受回调方法 该方法的此节向主应用程序线程发出信号,
//让它继续处理并建立与客户端的连接
allDone.Set();
// Get the socket that handles the client request.获取客户端请求句柄
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state =
new
StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new
AsyncCallback(ReadCallback), state);
}
catch
(Exception e)
{
//
}
}
/// <summary>
/// 与接受回调方法一样,读取回调方法也是一个 AsyncCallback 委托。
/// 该方法将来自客户端套接字的一个或多个字节读入数据缓冲区,然后再次调用 BeginReceive 方法,直到客户端发送的数据完成为止。
/// 从客户端读取整个消息后,在控制台上显示字符串,并关闭处理与客户端的连接的服务器套接字。
/// </summary>
/// <param name="ar">IAsyncResult 委托</param>
public
static
void
ReadCallback(IAsyncResult ar)
{
try
{
String content = String.Empty;
// Retrieve the state object and the handler socket创建自定义的状态对象 from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
//处理的句柄
// Read data from the client socket. 读出
int
bytesRead = handler.EndReceive(ar);
if
(bytesRead > 0)
{
//业务代码
string
result = DoSomeThing(...);
String len = Encoding.UTF8.GetBytes(result).Length.ToString().PadLeft(8,
'0'
);
log.writeLine(len);
Send(len + result, handler);
}
}
catch
(Exception e)
{
//
}
}
private
static
void
Send(String data, Socket handler)
{
try
{
// Convert the string data to byte data using UTF8 encoding.
byte
[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new
AsyncCallback(SendCallback), handler);
}
catch
(Exception e)
{
//
}
}
/// <summary>
/// 发送
/// </summary>
/// <param name="ar"></param>
private
static
void
SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.向远端发送数据
int
bytesSent = handler.EndSend(ar);
StateObject state =
new
StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new
AsyncCallback(ReadCallback), state);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch
(Exception e)
{
//
}
}
public
static
void
StopListening()
{
allDone.Close();
log.close();
}
/// <summary>
/// 具体处理业务的方法
/// </summary>
/// <returns></returns>
private
static
string
DoSomething(
int
i)
{
//具体业务代码,返回需要返回的字符串信息
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="strLog">写入内容</param>
public
static
void
WriteLog(
string
strLog)
{
//写入日志代码
}
}
|
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
/// 线程执行体,转发消息
/// </summary>
/// <param name="obj">传递给线程执行体的用户名,用以与用户通信 </param>
private
void
ThreadFunc(
object
obj)
{
//通过转发表得到当前用户套接字
Socket clientSkt = _transmit_tb[obj]
as
Socket;
//主循环
while
(
true
)
{
try
{
//接受第一个数据包。
//由于程序逻辑结构简单,所以在这里对客户机发送的第一个包内容作逐一判断,
//这里的实现不够优雅,但不失为此简单模型的一个解决之道。
byte
[] packetBuff =
new
byte
[_maxPacket];
clientSkt.Receive(packetBuff);
string
_str = Encoding.Unicode.GetString(packetBuff).TrimEnd(
'\0'
);
//如果是发给不在线好友的信息
if
(_str.StartsWith(
"cmd::FriendMessage"
))
{
string
UserName = _str.Substring(
"cmd::FriendMessage"
.Length, 20).Trim();
string
MessageS = _str.Substring(
"cmd::FriendMessage"
.Length + 20, _str.Length -
"cmd::FriendMessage"
.Length - 20);
SaveMessage(obj
as
string
, UserName, MessageS);
continue
;
}
//如果是离线请求
if
(_str.StartsWith(
"cmd::RequestLogout"
))
{
_transmit_tb.Remove(obj);
UpdateFriendList((
string
)obj,
false
,
""
);
// string svrlog = string.Format("[系统消息]用户 {0} 在 {1} 已断开... 当前在线人数: {2}\r\n\r\n", obj, DateTime.Now, _transmit_tb.Count);
// Console.WriteLine(svrlog);
//向所有客户机发送系统消息
//foreach (DictionaryEntry de in _transmit_tb)
//{
// string _clientName = de.Key as string;
// Socket _clientSkt = de.Value as Socket;
// _clientSkt.Send(Encoding.Unicode.GetBytes(svrlog));
//}
Thread.CurrentThread.Abort();
}
//如果是请求好友列表
if
(_str.StartsWith(
"cmd::RequestFriendList"
))
{
SerializeFriendList(obj, clientSkt);
// 将该用户不在线时的信息发送给用户
DataTable TabMessage = ReadMessage(obj
as
string
);
if
(TabMessage !=
null
)
{
foreach
(DataRow myrow
in
TabMessage.Rows)
{
if
(myrow[
"SendUserName"
].ToString() ==
"System::Message"
)
{
clientSkt.Send(Encoding.Unicode.GetBytes(myrow[
"Message"
].ToString()));
}
else
{
clientSkt.Send(Encoding.Unicode.GetBytes(
"cmd::FriendMessage"
+ myrow[
"SendUserName"
].ToString().PadRight(20,
' '
) + myrow[
"Message"
].ToString()));
}
}
}
//这里不需要再继续接受后继数据包了,跳出当前循环体。
continue
;
}
如果是请求好友列表
//if (_str.StartsWith("cmd::RequestOnLineList"))
//{
// byte[] onlineBuff = SerializeOnlineList();
// //先发送响应信号,用户客户机的判断
// clientSkt.Send(Encoding.Unicode.GetBytes("cmd::RequestOnLineList"));
// clientSkt.Send(onlineBuff);
// //这里不需要再继续接受后继数据包了,跳出当前循环体。
// continue;
//} //查找用户
if
(_str.StartsWith(
"Find::FindFriend"
))
{
DataTable TabFind = TabUser.Clone();
DataRow [] FindRow =
null
;
string
UserName = _str.Substring(
"Find::FindFriend"
.Length, _str.Length -
"Find::FindFriend"
.Length);
if
(UserName.Equals(
"Find::WhoOnLine"
))
{
//看谁在线
FindRow = TabUser.Select(
" ZX = 1"
);
}
else
//精确查找
{
FindRow = TabUser.Select(
"UserName = '"
+ UserName +
"'"
);
}
foreach
(DataRow myrow
in
FindRow)
{
TabFind.ImportRow(myrow);
}
clientSkt.Send(Encoding.Unicode.GetBytes(
"Find::FindFriend"
));
IFormatter format =
new
BinaryFormatter();
MemoryStream stream =
new
MemoryStream();
format.Serialize(stream, TabFind);
stream.Position = 0;
byte
[] ret =
new
byte
[_maxPacket];
int
count = 0;
count = stream.Read(ret, 0, _maxPacket);
while
(count >0)
{
clientSkt.Send(ret);
count = stream.Read(ret, 0, _maxPacket);
}
clientSkt.Send(Encoding.Unicode.GetBytes(
"Find::FindFriendEnd"
));
stream.Close();
TabFind =
null
;
FindRow =
null
;
//这里不需要再继续接受后继数据包了,跳出当前循环体。
continue
;
}
//请求添加好友
if
(_str.StartsWith(
"Find::AddFriendAsk"
))
{
string
UserName = _str.Substring(
"Find::AddFriendAsk"
.Length, _str.Length -
"Find::AddFriendAsk"
.Length);
//通过转发表查找接收方的套接字
if
(_transmit_tb.Count != 0 && _transmit_tb.ContainsKey(UserName))
{
Socket receiverSkt = _transmit_tb[UserName]
as
Socket;
receiverSkt.Send(Encoding.Unicode.GetBytes(
"Find::AddFriendAsk"
+ obj
as
string
));
}
//这里不需要再继续接受后继数据包了,跳出当前循环体。
continue
;
}
//回复答应添加好友
if
(_str.StartsWith(
"Find::AddFriendYes"
))
{
string
UserName = _str.Substring(
"Find::AddFriendYes"
.Length, _str.Length -
"Find::AddFriendYes"
.Length);
保存数据
DataTable TabmyFriend =
new
DataTable() ;
//保存该用户
TabmyFriend.ReadXml(MyPath +
"\\UserFriend\\"
+ obj
as
string
+
".xml"
);
DataRow newRow = TabmyFriend.NewRow();
newRow[
"UserName"
] = UserName;
TabmyFriend.Rows.Add(newRow);
TabmyFriend.WriteXml(MyPath +
"\\UserFriend\\"
+ obj
as
string
+
".xml"
, XmlWriteMode.WriteSchema,
false
);
//保存其好友
TabmyFriend =
new
DataTable();
TabmyFriend.ReadXml(MyPath +
"\\UserFriend\\"
+ UserName +
".xml"
);
DataRow newRow1 = TabmyFriend.NewRow();
newRow1[
"UserName"
] = obj
as
string
;
TabmyFriend.Rows.Add(newRow1);
TabmyFriend.WriteXml(MyPath +
"\\UserFriend\\"
+ UserName +
".xml"
, XmlWriteMode.WriteSchema,
false
);
TabmyFriend =
null
;
SerializeFriend
|
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
//"开始"按钮事件
private
void
button1_Click(
object
sender, System.EventArgs e) {
//取得预保存的文件名
string
fileName=textBox3.Text.Trim();
//远程主机
string
hostName=textBox1.Text.Trim();
//端口
int
port=Int32.Parse(textBox2.Text.Trim());
//得到主机信息
IPHostEntry ipInfo=Dns.GetHostByName(hostName);
//取得IPAddress[]
IPAddress[] ipAddr=ipInfo.AddressList;
//得到ip
IPAddress ip=ipAddr[0];
//组合出远程终结点
IPEndPoint hostEP=
new
IPEndPoint(ip,port);
//创建Socket 实例
Socket socket=
new
Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
try
{
//尝试连接
socket.Connect(hostEP);
}
catch
(Exception se)
{
MessageBox.Show(
"连接错误"
+se.Message,"提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//发送给远程主机的请求内容串
string
sendStr=
"GET / HTTP/1.1\r\nHost: "
+ hostName +
"\r\nConnection: Close\r\n\r\n"
;
//创建bytes字节数组以转换发送串
byte
[] bytesSendStr=
new
byte
[1024];
//将发送内容字符串转换成字节byte数组
bytesSendStr=Encoding.ASCII.GetBytes(sendStr);
try
{
//向主机发送请求
socket.Send(bytesSendStr,bytesSendStr.Length,0);
}
catch
(Exception ce)
{
MessageBox.Show(
"发送错误:"
+ce.Message,"提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//声明接收返回内容的字符串
string
recvStr=
""
;
//声明字节数组,一次接收数据的长度为1024字节
byte
[] recvBytes=
new
byte
[1024];
//返回实际接收内容的字节数
int
bytes=0;
//循环读取,直到接收完所有数据
while
(
true
)
{
bytes=socket.Receive(recvBytes,recvBytes.Length,0);
//读取完成后退出循环
if
(bytes〈=0)
break
;
//将读取的字节数转换为字符串
recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes);
}
//将所读取的字符串转换为字节数组
byte
[] content=Encoding.ASCII.GetBytes(recvStr);
try
{
//创建文件流对象实例
FileStream fs=
new
FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite);
//写入文件
fs.Write(content,0,content.Length);
}
catch
(Exception fe)
{
MessageBox.Show(
"文件创建/写入错误:"
+fe.Message,
"提示信息"
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//禁用Socket
socket.Shutdown(SocketShutdown.Both);
//关闭Socket
socket.Close();
}
}
|
TCP/UDP通讯
UDP的:
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
namespace
UDPServer
{
class
Program
{
static
void
Main(
string
[] args)
{
int
recv;
byte
[] data =
new
byte
[1024];
//构建TCP 服务器
//得到本机IP,设置TCP端口号
IPEndPoint ipep =
new
IPEndPoint(IPAddress.Any , 8001);
Socket newsock =
new
Socket(AddressFamily.InterNetwork, SocketType.Dgram , ProtocolType.Udp);
//绑定网络地址
newsock.Bind(ipep);
Console.WriteLine(
"This is a Server, host name is {0}"
,Dns.GetHostName());
//等待客户机连接
Console.WriteLine(
"Waiting for a client..."
);
//得到客户机IP
IPEndPoint sender =
new
IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);
recv = newsock.ReceiveFrom(data,
ref
Remote);
Console .WriteLine (
"Message received from {0}: "
, Remote.ToString ());
Console .WriteLine (Encoding .ASCII .GetString (data ,0,recv ));
//客户机连接成功后,发送欢迎信息
string
welcome =
"Welcome ! "
;
//字符串与字节数组相互转换
data = Encoding .ASCII .GetBytes (welcome );
//发送信息
newsock .SendTo (data ,data.Length ,SocketFlags .None ,Remote );
while
(
true
)
{
data =
new
byte
[1024];
//发送接受信息
recv =newsock.ReceiveFrom(data ,
ref
Remote);
Console .WriteLine (Encoding .ASCII .GetString (data ,0,recv));
newsock .SendTo (data ,recv ,SocketFlags .None ,Remote );
}
}
}
}
|
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Net;
using
System.Net.Sockets;
namespace
UDPClient
{
class
Program
{
static
void
Main(
string
[] args)
{
byte
[] data =
new
byte
[1024];
string
input ,stringData;
//构建TCP 服务器
Console.WriteLine(
"This is a Client, host name is {0}"
, Dns.GetHostName());
//设置服务IP,设置TCP端口号
IPEndPoint ipep =
new
IPEndPoint(IPAddress .Parse (
"127.0.0.1"
) , 8001);
//定义网络类型,数据连接类型和网络协议UDP
Socket server =
new
Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
string
welcome =
"Hello! "
;
data = Encoding.ASCII.GetBytes(welcome);
server.SendTo(data, data.Length, SocketFlags.None, ipep);
IPEndPoint sender =
new
IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)sender;
data =
new
byte
[1024];
int
recv = server.ReceiveFrom(data,
ref
Remote);
Console.WriteLine(
"Message received from {0}: "
, Remote.ToString());
Console.WriteLine(Encoding .ASCII .GetString (data,0,recv));
while
(
true
)
{
input = Console .ReadLine ();
if
(input ==
"exit"
)
break
;
server .SendTo (Encoding .ASCII .GetBytes (input ),Remote );
data =
new
byte
[1024];
recv = server.ReceiveFrom(data,
ref
Remote);
stringData = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(stringData);
}
Console .WriteLine (
"Stopping Client."
);
server .Close ();
}
}
}
|
简单的UDP
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
|
try
{
Socket s =
new
Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//向此网段发广播包
int
UDPListenerPort = 8082;
IPAddress broadcast = IPAddress.Parse(
"192.168.0.255"
);
//此处根据IP及子网掩码改为相应的广播IP
string
ts =
"This is UPD string for sending"
;
byte
[] sendbuf = Encoding.ASCII.GetBytes(ts);
IPEndPoint ep =
new
IPEndPoint(broadcast, UDPListenerPort);
s.SendTo(sendbuf, ep);
}
catch
(Exception e)
{}
|
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
UdpClient listener;
int
UDPListenerPort = 8082;
IPEndPoint groupEP =
new
IPEndPoint(IPAddress.Any, UDPListenerPort);
try
{
while
(
true
)
{
byte
[] bytes = listener.Receive(
ref
groupEP);
string
RecIP = groupEP.ToString().Substring(0, groupEP.ToString().IndexOf(
":"
));
//收到发送UPD端的IP
string
RecStr = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
//收到的UPD字符串
}
}
catch
{}
|
C#UDP的多路广播组的发送和接收
下列范例使用 UdpClient,在通讯端口11000传送UDP 资料包至多点传送位址群组 224.268.100.2。它传送命令列上指定的信息字串。
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
using
System;
using
System.Net;
using
System.Net.Sockets;
using
System.Text;
public
class
UDPMulticastSender {
private
static
IPAddress GroupAddress =
IPAddress.Parse(
"224.168.100.2"
);
private
static
int
GroupPort = 11000;
private
static
void
Send( String message) {
UdpClient sender =
new
UdpClient();
IPEndPoint groupEP =
new
IPEndPoint(GroupAddress,GroupPort);
try
{
Console.WriteLine(
"Sending datagram : {0}"
, message);
byte
[] bytes = Encoding.ASCII.GetBytes(message);
sender.Send(bytes, bytes.Length, groupEP);
sender.Close();
}
catch
(Exception e) {
Console.WriteLine(e.ToString());
}
}
public
static
int
Main(String[] args) {
Send(args[0]);
return
0;
}
}
|
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
using
System;
using
System.Net;
using
System.Net.Sockets;
using
System.Text;
public
class
UDPMulticastListener {
private
static
readonly
IPAddress GroupAddress =
IPAddress.Parse(
"224.168.100.2"
);
private
const
int
GroupPort = 11000;
private
static
void
StartListener() {
bool
done =
false
;
UdpClient listener =
new
UdpClient();
IPEndPoint groupEP =
new
IPEndPoint(GroupAddress,GroupPort);
try
{
listener.JoinMulticastGroup(GroupAddress);
listener.Connect(groupEP);
while
(!done) {
Console.WriteLine(
"Waiting for broadcast"
);
byte
[] bytes = listener.Receive(
ref
groupEP);
Console.WriteLine(
"Received broadcast from {0} :\n {1}\n"
,
groupEP.ToString(),
Encoding.ASCII.GetString(bytes,0,bytes.Length));
}
listener.Close();
}
catch
(Exception e) {
Console.WriteLine(e.ToString());
}
}
public
static
int
Main(String[] args) {
StartListener();
return
0;
}
}
|
C#TCP的:
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
TCPClient
TCPClient 类提供了一种使用 TCP 协议连接到某个端点的简化方法。它还通过 NetworkStream 对象展现在连接过程中读取或写入的数据。请参见下面从 QuickStart 文档中摘录的日期/时间客户机示例。
使用 C# 编写
using
System;
using
System.Net;
using
System.Net.Sockets;
using
System.IO;
using
System.Text;
class
Client
{
public
static
void
Main(String[] args)
{
TCPClient tcpc =
new
TCPClient();
Byte[] read =
new
Byte[32];
if
(args.Length != 1)
{
Console.WriteLine(“请在命令行中指定服务器名称”);
return
;
}
String server = args[0];
// 验证服务器是否存在
if
(DNS.GetHostByName(server) ==
null
)
{
Console.WriteLine(“找不到服务器:” + 服务器);
return
;
}
// 尝试连接到服务器
if
(tcpc.Connect(server, 13) == -1)
{
Console.WriteLine(“无法连接到服务器:” + 服务器);
return
;
}
// 获取流
Stream s = tcpc.GetStream();
// 读取流并将它转换为 ASCII 码形式
int
bytes = s.Read(read, 0, read.Length);
String Time = Encoding.ASCII.GetString(read);
// 显示数据
Console.WriteLine(“已接收到的” + 字节 + “字节”);
Console.WriteLine(“当前日期和时间是:” + 时间);
tcpc.Close();
}
}
TCPListener
TCPListener 类便于在来自某个客户机的 TCP 连接的特定套接字上进行侦听的工作。请参见下面包括在 QuickStart 文档中的日期/时间服务器示例。
使用 C# 编写
using
System;
using
System.Net;
using
System.Net.Sockets;
using
System.Text;
class
Server
{
public
static
void
Main()
{
DateTime now;
String strDateLine;
Encoding ASCII = Encoding.ASCII;
// 在端口 13 进行侦听
TCPListener tcpl =
new
TCPListener(13);
tcpl.Start();
Console.WriteLine(“正在等待客户进行连接”);
Console.WriteLine(“请按 Ctrl+c 退出...”);
while
(
true
)
{
// 接收会阻塞,直到有人连接上
Socket s = tcpl.Accept();
// 获取当前的日期和时间并将它连接成一个字符串
now = DateTime.Now;
strDateLine = now.ToShortDateString() +
" "
+
now.ToLongTimeString();
// 将该字符串转换成一个字节数组并发送它
Byte[] byteDateLine =
ASCII.GetBytes(strDateLine.ToCharArray());
s.Send(byteDateLine, byteDateLine.Length, 0);
Console.WriteLine(“发送” + strDateLine);
}
}
}
|
这个似乎是FTP下载的:
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
#region "Download: File transfer FROM ftp server"
/// <summary>
/// Copy a file from FTP server to local
/// </summary>
/// <param name="sourceFilename">Target filename, if required </param>
/// <param name="localFilename">Full path of the local file </param>
/// <returns> </returns>
/// <remarks>Target can be blank (use same filename), or just a filename
/// (assumes current directory) or a full path and filename </remarks>
public
bool
Download(
string
sourceFilename,
string
localFilename,
bool
PermitOverwrite)
{
//2. determine target file
FileInfo fi =
new
FileInfo(localFilename);
return
this
.Download(sourceFilename, fi, PermitOverwrite);
}
//Version taking an FtpFileInfo
public
bool
Download(FtpFileInfo file,
string
localFilename,
bool
permitOverwrite)
{
return
this
.Download(file.FullName, localFilename, permitOverwrite);
}
//Another version taking FtpFileInfo and FileInfo
public
bool
Download(FtpFileInfo file, FileInfo localFI,
bool
permitOverwrite)
{
return
this
.Download(file.FullName, localFI, permitOverwrite);
}
//Version taking string/FileInfo
public
bool
Download(
string
sourceFilename, FileInfo targetFI,
bool
permitOverwrite)
{
//1. check target
if
(targetFI.Exists && !(permitOverwrite))
{
throw
(
new
ApplicationException(
"Target file already exists"
));
}
//2. check source
string
target;
if
(sourceFilename.Trim() ==
""
)
{
throw
(
new
ApplicationException(
"File not specified"
));
}
else
if
(sourceFilename.Contains(
"/"
))
{
//treat as a full path
target = AdjustDir(sourceFilename);
}
else
{
//treat as filename only, use current directory
target = CurrentDirectory + sourceFilename;
}
string
URI = Hostname + target;
//3. perform copy
System.Net.FtpWebRequest ftp = GetRequest(URI);
//Set request to download a file in binary mode
ftp.Method = System.Net.WebRequestMethods.Ftp.DownloadFile;
ftp.UseBinary =
true
;
//open request and get response stream
using
(FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
{
using
(Stream responseStream = response.GetResponseStream())
{
//loop to read & write to file
using
(FileStream fs = targetFI.OpenWrite())
{
try
{
byte
[] buffer =
new
byte
[2048];
int
read = 0;
do
{
read = responseStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, read);
}
while
(!(read == 0));
responseStream.Close();
fs.Flush();
fs.Close();
}
catch
(Exception)
{
//catch error and delete file only partially downloaded
fs.Close();
//delete target file as it's incomplete
targetFI.Delete();
throw
;
}
}
responseStream.Close();
}
response.Close();
}
return
true
;
}
#endregion
|
似乎是发送MAIL的
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Net.Mail;
using
System.Diagnostics;
namespace
MailTest
{
class
Program
{
static
void
Main(
string
[] args)
{
Encoding encoding = Encoding.GetEncoding(
"GB2312"
);
MailAddress from =
new
MailAddress(
"youmailname@163.com"
,
"19850101"
, encoding);
MailAddress to =
new
MailAddress(
"youmailname@163.com"
);
MailMessage mail =
new
MailMessage(from, to);
mail.Subject =
"test"
;
mail.Body =
"hello world"
;
mail.SubjectEncoding = encoding;
mail.BodyEncoding = encoding;
SmtpClient smtp =
new
SmtpClient(
"smtp.163.com"
);
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.UseDefaultCredentials =
true
;
smtp.Credentials =
new
System.Net.NetworkCredential(
"rjgcwwdz@163.com"
,
"19850101"
);
smtp.Send(mail);
}
}
}
|
类似QQ通讯:
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Net;
using
System.IO;
using
System.Net.Sockets;
using
System.Threading;
namespace
MyQQSer
{
class
Serv
{
private
TcpListener listenr;
private
Thread thread;
private
bool
isClose =
false
;
//结束程序是退出循环
private
Socket[] sock =
new
Socket[50];
public
Serv()
{
Listener();
}
~Serv()
{
isClose =
true
;
for
(
int
i = 0; i < sock.Length; i++)
{
if
(sock[i] !=
null
)
sock[i].Close();
listenr.Stop();
}
}
/// <summary>
/// 开始监听端口
/// </summary>
public
void
Listener()
{
if
(listenr ==
null
)
listenr =
new
TcpListener(IPAddress.Parse(
"127.0.0.1"
), 5000);
listenr.Start();
if
(thread ==
null
)
thread =
new
Thread(
new
ThreadStart(ReciverMessage));
thread.IsBackground =
true
;
thread.Start();
}
/// <summary>
/// 接收数据
/// </summary>
private
void
ReciverMessage()
{
int
count;
//可用套结字索引
count = GetCount();
bool
loop =
true
;
if
(count == -1)
loop =
false
;
if
(loop)
{
while
(
true
)
{
// 判断是否退出循环
if
(isClose)
break
;
sock[count] = listenr.AcceptSocket();
Thread t =
new
Thread(
new
ThreadStart(ReciverMessage));
t.IsBackground =
true
;
t.Start();
// 接受客户端数据
while
(
true
)
{
byte
[] buffs =
new
byte
[100];
if
(sock[count].Connected)
{
try
{
sock[count].Receive(buffs);
string
message = Encoding.Default.GetString(buffs);
Console.WriteLine(message);
SendToAll(buffs);
}
catch
(Exception ex)
{
}
}
}
}
}
Thread.CurrentThread.Abort();
}
// 得到可用套结字索引
private
int
GetCount()
{
for
(
int
i = 0; i < sock.Length; i++)
if
(sock[i] ==
null
)
return
i;
return
-1;
}
// 发送消息给所有人
private
void
SendToAll(
byte
[] buff)
{
for
(
int
i = 0; i < sock.Length; i++)
{
if
(sock[i] !=
null
)
{
if
(sock[i].Connected)
{
sock[i].Send(buff);
}
}
}
}
}
}
|
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Text;
using
System.Windows.Forms;
using
System.Net.Sockets;
using
System.Net;
using
System.Threading;
using
System.IO;
namespace
TestClient
{
public
partial
class
Form1 : Form
{
private
TcpClient client;
private
Thread t;
private
Socket sock;
private
bool
close =
false
;
public
Form1()
{
InitializeComponent();
}
// 连接
private
void
btnConnect_Click(
object
sender, EventArgs e)
{
if
(client ==
null
)
client =
new
TcpClient(
new
IPEndPoint(IPAddress.Parse(
"127.0.0.1"
),
int
.Parse(txtLoalPort.Text)));
if
(t ==
null
)
t =
new
Thread(
new
ThreadStart(ReciverMessage));
t.IsBackground =
true
;
t.Start();
btnSend.Enabled =
true
;
btnConnect.Enabled =
false
;
}
// 接收消息
private
void
ReciverMessage()
{
client.Connect(IPAddress.Parse(txtSerIP.Text),
int
.Parse(txtSerPort.Text));
while
(
true
)
{
if
(close)
break
;
//NetworkStream nws = client.GetStream();
//StreamReader sr = new StreamReader(nws);
//string message = sr.ReadToEnd();
//sr.Close();
if
(sock ==
null
)
sock = client.Client;
byte
[] buff =
new
byte
[100];
sock.Receive(buff);
string
message = Encoding.Default.GetString(buff);
this
.lstMessage.Items.Add(message);
}
Thread.CurrentThread.Abort();
}
// 发送消息
private
void
btnSend_Click(
object
sender, EventArgs e)
{
string
message =
this
.txtInput.Text;
byte
[] buff = Encoding.Default.GetBytes(message);
sock.Send(buff);
txtInput.Text =
""
;
}
private
void
Form1_FormClosing(
object
sender, FormClosingEventArgs e)
{
close =
true
;
sock.Close();
}
}
}
|
还有个remoting的:
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
using
System;
namespace
Remotable
{
public
class
RemotableType : MarshalByRefObject
{
private
string
_internalString =
"This is the RemotableType."
;
public
string
StringMethod()
{
return
_internalString;
}
}
}
using
System;
using
System.Runtime.Remoting;
namespace
RemotingFirst
{
public
class
Listener
{
public
static
void
Main()
{
RemotingConfiguration.Configure(
"Listener.exe.config"
);
Console.WriteLine(
"Listening for requests. Press Enter to exit"
);
Console.ReadLine();
}
}
}
using
System;
using
System.Runtime.Remoting;
namespace
Client
{
public
class
Client
{
public
static
void
Main()
{
RemotingConfiguration.Configure(
"Client.exe.config"
);
Remotable.RemotableType remoteObject =
new
Remotable.RemotableType();
Console.WriteLine(remoteObject.StringMethod());
}
}
}
Listener.exe.config
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
mode=
"Singleton"
type=
"Remotable.RemotableType, RemotableType"
objectUri=
"RemotableType.rem"
/>
</service>
<channels>
<channel
ref
=
"http"
port=
"8989"
/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
|
一个通讯类,类似教程的:
实只要用到Socket联接,基本上就得使用Thread,是交叉使用的。
C#封装的Socket用法基本上不算很复杂,只是不知道托管之后的Socket有没有其他性能或者安全上的问题。
在C#里面能找到的最底层的操作也就是socket了,概念不做解释。
程序模型如下:
WinForm程序 : 启动端口侦听;监视Socket联接情况;定期关闭不活动的联接;
Listener:处理Socket的Accept函数,侦听新链接,建立新Thread来处理这些联接(Connection)。
Connection:处理具体的每一个联接的会话。
1:WinForm如何启动一个新的线程来启动Listener:
//start the server
private void btn_startServer_Click(object sender, EventArgs e)
{
//this.btn_startServer.Enabled = false;
Thread _createServer = new Thread(new ThreadStart(WaitForConnect));
_createServer.Start();
}
//wait all connections
private void WaitForConnect()
{
SocketListener listener = new SocketListener(Convert.ToInt32(this.txt_port.Text));
listener.StartListening();
}
因为侦听联接是一个循环等待的函数,所以不可能在WinForm的线程里面直接执行,不然Winform也就是无法继续任何操作了,所以才指定一个新的线程来执行这个函数,启动侦听循环。
这一个新的线程是比较简单的,基本上没有启动的参数,直接指定处理函数就可以了。
2:Listener如何启动循环侦听,并且启动新的带有参数的线程来处理Socket联接会话。
先看如何建立侦听:(StartListening函数)
IPEndPoint localEndPoint = new IPEndPoint(_ipAddress, _port);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(20);//20 trucks
// Start listening for connections.
while (true)
{
// here will be suspended while waiting for a new connection.
Socket connection = listener.Accept();
Logger.Log("Connect", connection.RemoteEndPoint.ToString());//log it, new connection
……
}
}……
基本步骤比较简单:
建立本机的IPEndPoint对象,表示以本机为服务器,在指定端口侦听;
然后绑定到一个侦听Socket上;
进入while循环,等待新的联接;
如果有新的联接,那么建立新的socket来对应这个联接的会话。
值得注意的就是这一句联接代码:listener.Accept()。执行这一句的时候,程序就在这个地方等待,直到有新的联检请求的时候程序才会执行下一句。这是同步执行,当然也可以异步执行。
新的联接Socket建立了(Accept之后),对于这些新的socket该怎么办呢?他们依然是一个循环等待,所以依然需要建立新的Thread给这些Socket去处理会话(接收/发送消息),而这个Thread就要接收参数了。
Thread本身是不能接收参数的,为了让它可以接收参数,可以采用定义新类,添加参数作为属性的方法来解决。
因为每一个Socket是一个Connection周期,所以我定义了这么一个类public class Connection。这个类至少有这样一个构造函数public Connection(Socket socket); 之所以这么做,就是为了把Socket参数传给这个Connection对象,然后好让Listener启动这个Thread的时候,Thread可以知道他正在处理哪一个Socket。
具体处理的方法:(在Listener的StartListening函数,ocket connection = listener.Accept();之后)
Connection gpsCn = new Connection(connection);
//each socket will be wait for data. keep the connection.
Thread thread = new Thread(new ThreadStart(gpsCn.WaitForSendData));
thread.Name = connection.RemoteEndPoint.ToString();
thread.Start();
如此一来,这个新的socket在Accept之后就在新的Thread中运行了。
3:Connection的会话处理
建立了新的Connection(也就是socket),远程就可以和这个socket进行会话了,无非就是send和receive。
现在先看看怎么写的这个线程运行的Connection. WaitForSendData函数
while (true)
{
bytes = new byte[1024];
string data = "";
//systm will be waiting the msg of receive envet. like Accept();
//here will be suspended while waiting for socket income msg.
int bytesRec = this._connection.Receive(bytes);
_lastConnectTime = DateTime.Now;
if (bytesRec == 0)//close envent
{
Logger.Log("Close Connection", _connection.RemoteEndPoint.ToString());
break;
}
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
//…….handle your data.
}
可以看到这个处理的基本步骤如下:
执行Receive函数,接收远程socket发送的信息;
把信息从字节转换到string;
处理该信息,然后进入下一个循环,继续等待socket发送新的信息。
值得注意的有几个:
1:Receive函数。这个函数和Listener的Accept函数类似。在这个地方等待执行,如果没有新的消息,这个函数就不会执行下一句,一直等待。
2:接收的是字节流,需要转化成字符串
3:判断远程关闭联接的方式
4:如果对方的消息非常大,还得循环接收这个data。
4:如何管理这些联接(thread)
通过上边的程序,基本上可以建立一个侦听,并且处理联接会话。但是如何管理这些thread呢?不然大量产生thread可是一个灾难。
管理的方法比较简单,在Listener里面我定义了一个静态的哈希表(static public Hashtable Connections=new Hashtable();),存储Connection实例和它对应的Thread实例。而connection中也加入了一个最后联接时间的定义(private DateTime _lastConnectTime;)。在新链接建立的时候(Listener的Accept()之后)就把Connection实例和Thread实例存到哈希表中;在Connection的Receive的时候修改最后联接时间。这样我们就可以知道该Connection在哪里,并且会话是否活跃。
然后在Winform程序里头可以管理这些会话了,设置设置超时。
在网络环境下,我们最感兴趣的两个命名空间是System.Net和 System.Net.Sockets。System.Net命名空间通常与较高程的操作有关,例如download或upload,试用HTTP和其他协议进行Web请求等等,而System.Net.Sockets命名空间所包含的类通常与较低程的操作有关。如果要直接使用Sockets或者 TCP/IP之类的协议,这个命名空间的类是非常有用的。
在.Net中,System.Net.Sockets 命名空间为需要严密控制网络访问的开发人员提供了 Windows Sockets (Winsock) 接口的托管实现。System.Net 命名空间中的所有其他网络访问类都建立在该套接字Socket实现之上,如TCPClient、TCPListener 和 UDPClient 类封装有关创建到 Internet 的 TCP 和 UDP 连接的详细信息;NetworkStream类则提供用于网络访问的基础数据流等,常见的许多Internet服务都可以见到Socket的踪影,如 Telnet、Http、Email、Echo等,这些服务尽管通讯协议Protocol的定义不同,但是其基础的传输都是采用的Socket。
其实,Socket可以象流Stream一样被视为一个数据通道,这个通道架设在应用程序端(客户端)和远程服务器端之间,而后,数据的读取(接收)和写入(发送)均针对这个通道来进行。
可见,在应用程序端或者服务器端创建了Socket对象之后,就可以使用Send/SentTo方法将数据发送到连接的Socket,或者使用Receive/ReceiveFrom方法接收来自连接Socket的数据。
针对Socket编程,.NET 框架的 Socket 类是 Winsock32 API 提供的套接字服务的托管代码版本。其中为实现网络编程提供了大量的方法,大多数情况下,Socket 类方法只是将数据封送到它们的本机 Win32 副本中并处理任何必要的安全检查。如果你熟悉Winsock API函数,那么用Socket类编写网络程序会非常容易,当然,如果你不曾接触过,也不会太困难,跟随下面的解说,你会发觉使用Socket类开发 windows 网络应用程序原来有规可寻,它们在大多数情况下遵循大致相同的步骤。
在使用之前,你需要首先创建Socket对象的实例,这可以通过Socket类的构造方法来实现:
public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);
其中,addressFamily 参数指定 Socket 使用的寻址方案,socketType 参数指定 Socket 的类型,protocolType 参数指定 Socket 使用的协议。
下面的示例语句创建一个 Socket,它可用于在基于 TCP/IP 的网络(如 Internet)上通讯。
Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
若要使用 UDP 而不是 TCP,需要更改协议类型,如下面的示例所示:
Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
一旦创建 Socket,在客户端,你将可以通过Connect方法连接到指定的服务器,并通过Send/SendTo方法向远程服务器发送数据,而后可以通过 Receive/ReceiveFrom从服务端接收数据;而在服务器端,你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联,并通过Listen方法侦听该接口上的请求,当侦听到用户端的连接时,调用Accept完成连接的操作,创建新的Socket以处理传入的连接请求。使用完 Socket 后,记住使用 Shutdown 方法禁用 Socket,并使用 Close 方法关闭 Socket。
可以看出,以上许多方法包含EndPoint类型的参数,在Internet中,TCP/IP 使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备;端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点,在 .NET 框架中正是由 EndPoint 类表示这个终结点,它提供表示网络资源或服务的抽象,用以标志网络地址等信息。.Net同时也为每个受支持的地址族定义了 EndPoint 的子代;对于 IP 地址族,该类为 IPEndPoint。IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息,通过组合服务的主机IP地址和端口号,IPEndPoint 类形成到服务的连接点。
用到IPEndPoint类的时候就不可避免地涉及到计算机IP地址,System.Net命名空间中有两种类可以得到IP地址实例:
IPAddress类:IPAddress 类包含计算机在 IP 网络上的地址。其Parse方法可将 IP 地址字符串转换为 IPAddress 实例。下面的语句创建一个 IPAddress 实例:
IPAddress myIP = IPAddress.Parse("192.168.0.1");
Dns 类:向使用 TCP/IP Internet 服务的应用程序提供域名服务。其Resolve 方法查询 DNS 服务器以将用户友好的域名(如"host.mydomain.com")映射到数字形式的 Internet 地址(如 192.168.0.1)。Resolve方法 返回一个 IPHostEnty 实例,该实例包含所请求名称的地址和别名的列表。大多数情况下,可以使用 AddressList 数组中返回的第一个地址。下面的代码获取一个 IPAddress 实例,该实例包含服务器 host.mydomain.com 的 IP 地址。
IPHostEntry ipHostInfo = Dns.Resolve("host.mydomain.com ");
IPAddress ipAddress = ipHostInfo.AddressList[0];
你也可以使用GetHostName方法得到IPHostEntry实例:
IPHosntEntry hostInfo=Dns.GetHostByName("host.mydomain.com ")
在使用以上方法时,你将可能需要处理以下几种异常:
SocketException异常:访问Socket时操作系统发生错误引发
ArgumentNullException异常:参数为空引用引发
ObjectDisposedException异常:Socket已经关闭引发
在掌握上面得知识后,下面的代码将该服务器主机( host.mydomain.com的 IP 地址与端口号组合,以便为连接创建远程终结点:
IPEndPoint ipe = new IPEndPoint(ipAddress,11000);
确定了远程设备的地址并选择了用于连接的端口后,应用程序可以尝试建立与远程设备的连接。下面的示例使用现有的 IPEndPoint 实例与远程设备连接,并捕获可能引发的异常:
try
{
temp.Connect(ipe);//尝试连接
}
//处理参数为空引用异常
catch(ArgumentNullException ae)
{
Console.WriteLine("ArgumentNullException : {0}", ae.ToString());
}
//处理操作系统异常
catch(SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
需要知道的是:Socket 类支持两种基本模式:同步和异步。其区别在于:在同步模式中,对执行网络操作的函数(如 Send 和 Receive)的调用一直等到操作完成后才将控制返回给调用程序。在异步模式中,这些调用立即返回。
综合运用以上阐述的使用Visual C#进行Socket网络程序开发的知识,下面的程序是一个简单的Socket通讯实例,client向server发送一段测试字符串,server接收并显示出来,给予client成功相应。
//client端
using System;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace socketsample
{
class Class1
{
static void Main()
{
try
{
int port = 2000;
string host = "127.0.0.1";
IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);
Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
c.Connect(ipe);
string sendStr = "hello!This is a socket test";
byte[] bs = Encoding.ASCII.GetBytes(sendStr);
c.Send(bs, bs.Length, 0);
string recvStr = "";
byte[] recvBytes = new byte[1024];
int bytes;
bytes = c.Receive(recvBytes, recvBytes.Length, 0);
recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
Console.WriteLine(recvStr);
c.Close();
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
Console.ReadLine();
}
}
}
//server端
using System;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace Project1
{
class Class2
{
static void Main()
{
try
{
int port = 2000;
string host = "127.0.0.1";
IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.Bind(ipe);
s.Listen(0);
Socket temp = s.Accept();
string recvStr = "";
byte[] recvBytes = new byte[1024];
int bytes;
bytes = temp.Receive(recvBytes, recvBytes.Length, 0);
recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
Console.WriteLine(recvStr);
string sendStr = "Ok!Sucess!";
byte[] bs = Encoding.ASCII.GetBytes(sendStr);
temp.Send(bs, bs.Length, 0);
temp.Shutdown(SocketShutdown.Both);
temp.Close();
s.Shutdown(SocketShutdown.Both);
s.Close();
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
Console.ReadLine();
}
}
}
以上程序在VS Express 2005 .Net2.0环境下测试通过。
koobee学生在校写的《银证转帐系统》的通信代码
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Net;
using
System.Net.Sockets;
using
System.Threading;
using
System.Windows.Forms;
using
System.IO;
using
System.Data.SqlClient;
namespace
SERVERsocket
{
class
SERVER
{
private
Thread serverThread;
private
Thread recvThread;
private
TcpListener tcpListener;
private
NetworkStream networkStream;
private
StreamReader streamReader;
private
StreamWriter streamWriter;
private
Socket socketForClient;
private
string
message;
private
int
operatorNO;
private
bool
[] isOperated;
private
void
Listen()
{
try
{
Int32 port = Int32.Parse(
"2020"
);
IPAddress ipAddress = Dns.Resolve(
"localhost"
).AddressList[0];
tcpListener =
new
TcpListener(IPAddress.Any, port);
//开始侦听
tcpListener.Start();
//返回可以用以处理连接的Socket实例
socketForClient = tcpListener.AcceptSocket();
if
(socketForClient.Connected)
{
networkStream =
new
NetworkStream(socketForClient);
streamReader =
new
StreamReader(networkStream);
streamWriter =
new
StreamWriter(networkStream);
recvThread =
new
Thread(
new
ThreadStart(RecvData));
recvThread.Start();
}
MessageBox.Show(
"客户端成功连接上服务器!"
);
}
catch
(Exception exc)
{
MessageBox.Show(exc.Message,
"Server提示"
);
}
}
//接收数据
private
void
RecvData()
{
string
msg = streamReader.ReadLine();
string
[] tokens = msg.Split(
new
char
[] {
'#'
});
//MessageBox.Show(tokens[0]);
//MessageBox.Show(tokens[1]);
//MessageBox.Show(tokens[2]);
while
(!msg.Equals(
"clientExit"
))
{
switch
(tokens[0])
{
case
"c01"
:
{
//MessageBox.Show("开始登陆!");
//下面写SQL语句,查询对应的帐户密码是否正确,并返回信息
SqlConnection thisConnection =
new
SqlConnection(
"server = localhost;Integrated Security =true;database = security"
);
SqlCommand comn =
new
SqlCommand(
"select 密码 from 帐户表 where 账号="
+ tokens[1], thisConnection);
thisConnection.Open();
SqlDataAdapter thisAdapt =
new
SqlDataAdapter(
"select * from 帐户表"
, thisConnection);
DataSet thisDataSet =
new
DataSet();
thisAdapt.Fill(thisDataSet,
"帐户表"
);
string
s = comn.ExecuteScalar().ToString();
// MessageBox.Show(s);
// MessageBox.Show(tokens[2]);
if
(s.CompareTo(tokens[2]) == 0)
{
streamWriter.Write(
"1"
);
streamWriter.Flush();
tokens[0].Remove(0);
// MessageBox.Show("登陆消息已发送");
}
else
{
streamWriter.Write(
"1"
);
streamWriter.Flush();
tokens[0].Remove(0);
// MessageBox.Show("登陆");
}
}
break
;
case
"c02"
:
{
//下面写SQL语句,查询对应账户的余额,并返回信息
SqlConnection thisConnection =
new
SqlConnection(
"server = localhost;Integrated Security =true;database = security;"
);
SqlDataAdapter thisAdapt =
new
SqlDataAdapter(
"select * from 帐户表"
, thisConnection);
SqlCommandBuilder thisbuider =
new
SqlCommandBuilder(thisAdapt);
SqlCommand thisCommand = thisConnection.CreateCommand();
thisConnection.Open();
DataSet thisDataSet =
new
DataSet();
thisAdapt.Fill(thisDataSet,
"帐户表"
);
string
s1 =
"select 金额 from 帐户表 where 账号="
+ tokens[1];
setMessage(
"c002#"
+ s1);
//填写账户余额
SendData();
tokens[0].Remove(0);
}
break
;
case
"c03"
:
{
//更改帐户密码的sql语句,完成后返回数据003成功
SqlConnection thisConnection =
new
SqlConnection(
"server = localhost;Integrated Security =true;database = security;"
);
SqlDataAdapter thisAdapt =
new
SqlDataAdapter(
"select * from 帐户表"
, thisConnection);
SqlCommandBuilder thisbuider =
new
SqlCommandBuilder(thisAdapt);
SqlCommand thisCommand = thisConnection.CreateCommand();
thisConnection.Open();
DataSet thisDataSet =
new
DataSet();
thisAdapt.Fill(thisDataSet,
"帐户表"
);
foreach
(DataRow rows
in
thisDataSet.Tables[
"帐户表"
].Rows)
{
string
s1 =
"select 密码 from 帐户表 where 账号="
+ tokens[1];
if
(s1.CompareTo(tokens[1]) == 0)
{
thisCommand.CommandText =
"update 帐户表 set 密码 = "
+ tokens[3] +
"where 账号="
+ tokens[1];
setMessage(
"c003#1"
);
//修改密码成功
SendData();
tokens[0].Remove(0);
}
else
{
setMessage(
"c003#2"
);
//修改密码失败
SendData();
tokens[0].Remove(0);
}
}
}
break
;
|
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
case
"c04"
:
{
operatorNO = Int32.Parse(tokens[1]);
if
(isOperated[operatorNO])
//这句要查下,c#中的bool初始值是什么?true还是false
{
SendData();
isOperated[operatorNO] =
true
;
//将“已操作”标记设置为true
}
else
{
//执行转账操作的SQL语句,完成后并返回信息
SqlConnection thisConnection =
new
SqlConnection(
"server = localhost;Integrated Security =true;database = security;"
);
SqlDataAdapter thisAdapt =
new
SqlDataAdapter(
"select * from 帐户表"
, thisConnection);
thisConnection.Open();
SqlCommand thisCommand = thisConnection.CreateCommand();
DataSet thisDataSet =
new
DataSet();
thisAdapt.Fill(thisDataSet,
"帐户表"
);
string
s2 =
"select 金额 from 帐户表 where 账号="
+ tokens[1];
string
s3 =
"select 金额 from 帐户表 where 账号="
+ tokens[1];
if
(s2.CompareTo(tokens[3]) < 0)
setMessage(
"c004#1"
);
else
if
(s3 ==
null
)
setMessage(
"c004#2"
);
else
{
foreach
(DataRow rows
in
thisDataSet.Tables[
"帐户表"
].Rows)
{
if
(rows[
"账号"
].ToString() == tokens[1])
thisCommand.CommandText =
"update 帐户表 set 金额 = 金额 -"
+ tokens[3] +
"where 账号="
+ tokens[1];
if
(rows[
"账号"
].ToString() == tokens[2])
thisCommand.CommandText =
"update 帐户表 set 金额 = 金额 +"
+ tokens[3] +
"where 账号="
+ tokens[2];
}
setMessage(
"c004#3"
);
}
SendData();
tokens[0].Remove(0);
isOperated[operatorNO] =
true
;
//将“已操作”标记设置为true
}
}
break
;
case
"c05"
:
{
operatorNO = Int32.Parse(tokens[1]);
if
(isOperated[operatorNO])
//这句要查下,c#中的bool初始值是什么?true还是false
{
SendData();
isOperated[operatorNO] =
true
;
//将“已操作”标记设置为true
}
else
{
//执行转账操作的SQL语句,完成后并返回信息
}
SendData();
tokens[0].Remove(0);
isOperated[operatorNO] =
true
;
//将“已操作”标记设置为true
}
break
;
}
msg = streamReader.ReadLine();
}
MessageBox.Show(
"一名客户退出"
);
ReleaseResource();
startServer();
}
public
void
setMessage(
string
message)
{
this
.message = message;
}
private
void
SendData()
{
streamWriter.Write(message);
streamWriter.Flush();
//streamWriter.Close();
}
private
void
ReleaseResource()
{
if
(networkStream !=
null
)
{
networkStream.Close();
streamReader.Close();
streamWriter.Close();
socketForClient.Shutdown(SocketShutdown.Both);
socketForClient.Close();
tcpListener.Stop();
}
}
public
void
startServer()
{
serverThread =
new
Thread(
new
ThreadStart(Listen));
serverThread.Start();
}
public
void
serverExit()
{
string
exitMsg =
"serverExit"
;
//要退出时,发送exit信息给服务器
setMessage(exitMsg);
SendData();
ReleaseResource();
}
}
|
C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
public
partial
class
BankClient
{
private
NetworkStream networkStream;
private
StreamReader streamReader;
private
StreamWriter streamWriter;
private
TcpClient myclient;
private
Thread recvThread;
private
Thread sendThread;
private
Thread serverThread;
private
bool
flag =
true
;
private
void
Connection()
{
try
{
Int32 port = 8888;
myclient =
new
TcpClient(
"10.1.1.10"
, port);
}
catch
{
MessageBox.Show(
"没有连接到银行服务器!"
);
}
networkStream = myclient.GetStream();
streamReader =
new
StreamReader(networkStream);
streamWriter =
new
StreamWriter(networkStream);
// recvThread = new Thread(new ThreadStart(RecvData));
// recvThread.Start();
MessageBox.Show(
"连接到银行服务器!"
);
}
private
void
RecvData()
{
string
s = streamReader.ReadLine();
string
[] tokens = s.Split(
new
char
[] {
'#'
});
while
(!s.Equals(
"severExit"
))
{
if
(tokens[0] ==
"1"
)
{
SqlConnection thisConnection =
new
SqlConnection(
"server = localhost;Integrated Security = true;database = security;"
);
SqlDataAdapter thisAdapt =
new
SqlDataAdapter(
"select * from 转账接口表"
, thisConnection);
SqlCommandBuilder thisbuider =
new
SqlCommandBuilder(thisAdapt);
SqlCommand thisCommand = thisConnection.CreateCommand();
DataSet thisSet =
new
DataSet();
thisAdapt.Fill(thisSet,
"转账接口表"
);
thisConnection.Open();
// thisCommand.CommandText = "update 转账接口表 set 标志位 = 3" + "where 转账序号=" + tokens[1];
thisCommand.CommandText =
"delete from 转账接口表 where 转账序号="
+ tokens[1];
thisCommand.ExecuteNonQuery();
flag =
true
;
}
else
flag =
false
;
s = streamReader.ReadLine();
}
ReleaseResouce();
}
private
void
SendData()
{
SqlConnection thisConnection =
new
SqlConnection(
"server = localhost;Integrated Security = true;database = security;"
);
SqlDataAdapter thisAdapt =
new
SqlDataAdapter(
"select * from 转账接口表"
, thisConnection);
SqlCommandBuilder thisbuider =
new
SqlCommandBuilder(thisAdapt);
SqlCommand thisCommand = thisConnection.CreateCommand();
DataSet thisSet =
new
DataSet();
thisAdapt.Fill(thisSet,
"转账接口表"
);
thisConnection.Open();
foreach
(DataRow rows
in
thisSet.Tables[
"转账接口表"
].Rows)
{
if
(rows[
"标志位"
].ToString() ==
"1"
)
{
string
s;
s = rows[
"转账序号"
].ToString() +
'#'
+ rows[
"发起端账号"
].ToString() +
'#'
+ rows[
"接收端账号"
].ToString() +
'#'
+ rows[
"发生金额"
] +
'#'
+ rows[
"标志位"
].ToString();
if
(flag)
{
streamWriter =
new
StreamWriter(networkStream);
streamWriter.WriteLine(s);
streamWriter.Flush();
System.Threading.Thread.Sleep(5000);
}
else
{
//将数据读入资金变更表
thisCommand.CommandText =
"delete from 转账接口表 where 标志位= '3'"
;
}
}
}
}
private
void
ReleaseResouce()
{
networkStream.Close();
streamReader.Close();
streamWriter.Close();
sendThread.Abort();
//serverThread.Abort();
myclient.Close();
}
public
void
startBankClient( )
{
serverThread =
new
Thread(
new
ThreadStart(Connection));
serverThread.Start();
int
row = 0;
SqlConnection thisConnection =
new
SqlConnection(
"server = localhost;Integrated Security = true;database = security;"
);
SqlDataAdapter thisAdapt =
new
SqlDataAdapter(
"select * from 转账接口表"
, thisConnection);
SqlCommandBuilder thisbuider =
new
SqlCommandBuilder(thisAdapt);
DataSet thisSet =
new
DataSet();
thisAdapt.Fill(thisSet,
"转账接口表"
);
while
(
true
)
{
foreach
(DataRow rows
in
thisSet.Tables[
"转账接口表"
].Rows)
{
row++;
}
if
(row > 0)
{
SendData();
RecvData();
}
System.Threading.Thread.Sleep(5000);
}
}
public
void
exitBankClient( )
{
streamWriter.Flush();
ReleaseResouce();
}
}
}
(福建师范大学软件学院)
|