在一个blog上看到的好帖,写了一个对网络 socket 进行封装的类,主要是在异步阻塞模式下进行数据、文件的发送的发送和接收,都是静态方法。代码如下:
1
using
System;
2
using
System.Net ;
3
using
System.Net.Sockets ;
4
using
System.IO ;
5
using
LogDll;
6

7
namespace
NetDll
8

{
9
// <summary>
10
/// Net : 提供静态方法,对常用的网络操作进行封装
11
/// </summary>
12
public sealed class Net
13
{
14
private Net(){
15
}
16
17
/**//// <summary>
18
/// 连接使用 tcp 协议的服务端
19
/// </summary>
20
/// <param name="ip">服务端的ip地址</param>
21
/// <param name="port">服务端的端口号</param>
22
/// <returns></returns>
23
public static Socket ConnectServer( string ip ,int port ) {
24
Socket s = null;
25
26
try {
27
IPAddress ipAddress = IPAddress.Parse ( ip );
28
IPEndPoint ipEndPoint = new IPEndPoint ( ipAddress,port );
29
s = new Socket ( ipEndPoint.AddressFamily ,SocketType.Stream ,ProtocolType.Tcp );
30
s.Connect ( ipEndPoint );
31
if ( s.Connected== false ) {
32
s = null;
33
}
34
}
35
catch ( Exception e ) {
36
Log.WriteLog ( e );
37
}
38
return s;
39
}
40
41
/**//// <summary>
42
/// 用主机名称连接使用Tcp协议的服务端
43
/// </summary>
44
/// <param name="hostName">在hosts 文件中存在的主机名称</param>
45
/// <param name="port">服务端的端口号</param>
46
/// <returns></returns>
47
public static Socket ConnectServByHostName( string hostName,int port ){
48
Socket s = null;
49
IPHostEntry iphe = null;
50
51
try {
52
iphe = Dns.Resolve ( hostName );
53
foreach ( IPAddress ipad in iphe.AddressList ) {
54
IPEndPoint ipe = new IPEndPoint (ipad,port);
55
Socket tmps = new Socket (ipe.AddressFamily ,SocketType.Stream ,ProtocolType.Tcp );
56
tmps.Connect ( ipe );
57
58
if ( tmps.Connected ) {
59
s = tmps;
60
break;
61
}
62
else
63
continue;
64
}
65
}
66
catch ( Exception e ) {
67
Log.WriteLog ( e );
68
}
69
return s;
70
}
71
72
/**//// <summary>
73
/// 向远程主机发送数据
74
/// </summary>
75
/// <param name="socket">要发送数据且已经连接到远程主机的 Socket</param>
76
/// <param name="buffer">待发送的数据</param>
77
/// <param name="outTime">发送数据的超时时间,以秒为单位,可以精确到微秒</param>
78
/// <returns>0:发送数据成功;-1:超时;-2:发送数据出现错误;-3:发送数据时出现异常</returns>
79
/// <remarks >
80
/// 当 outTime 指定为-1时,将一直等待直到有数据需要发送
81
/// </remarks>
82
public static int SendData ( Socket socket,byte[] buffer,int outTime ) {
83
if ( socket == null ||socket.Connected == false ) {
84
throw new ArgumentException ("参数socket 为null,或者未连接到远程计算机");
85
}
86
if ( buffer == null || buffer.Length == 0 ) {
87
throw new ArgumentException ("参数buffer 为null ,或者长度为 0");
88
}
89
90
int flag = 0;
91
try {
92
int left = buffer.Length ;
93
int sndLen = 0;
94
95
while ( true ) {
96
if ( ( socket.Poll (outTime*1000000,SelectMode.SelectWrite ) == true ) ) { // 收集了足够多的传出数据后开始发送
97
sndLen = socket.Send (buffer,sndLen ,left ,SocketFlags.None );
98
left -= sndLen ;
99
if ( left == 0 ) // 数据已经全部发送
100
flag = 0;
101
break;
102
}
103
else {
104
if ( sndLen > 0 ) { // 数据部分已经被发送
105
continue;
106
}
107
else { // 发送数据发生错误
108
flag = -2;
109
break;
110
}
111
}
112
}
113
else { // 超时退出
114
flag = -1;
115
break;
116
}
117
}
118
}
119
catch ( SocketException e ) {
120
Log.WriteLog ( e );
121
flag = -3;
122
}
123
return flag;
124
}
125
126
127
/**//// <summary>
128
/// 向远程主机发送数据
129
/// </summary>
130
/// <param name="socket">要发送数据且已经连接到远程主机的 Socket</param>
131
/// <param name="buffer">待发送的字符串</param>
132
/// <param name="outTime">发送数据的超时时间,以秒为单位,可以精确到微秒</param>
133
/// <returns>0:发送数据成功;-1:超时;-2:发送数据出现错误;-3:发送数据时出现异常</returns>
134
/// <remarks >
135
/// 当 outTime 指定为-1时,将一直等待直到有数据需要发送
136
/// </remarks>
137
public static int SendData ( Socket socket,string buffer,int outTime ) {
138
if ( buffer == null || buffer.Length == 0 ) {
139
throw new ArgumentException ("待发送的字符串长度不能为零.");
140
}
141
return ( SendData ( socket,System.Text .Encoding .Default .GetBytes ( buffer ),outTime) );
142
}
143
144
145
/**//// <summary>
146
/// 接收远程主机发送的数据
147
/// </summary>
148
/// <param name="socket">要接收数据且已经连接到远程主机的 socket</param>
149
/// <param name="buffer">接收数据的缓冲区</param>
150
/// <param name="outTime">接收数据的超时时间,以秒为单位,可以精确到微秒</param>
151
/// <returns>0:接收数据成功;-1:超时;-2:接收数据出现错误;-3:接收数据时出现异常</returns>
152
/// <remarks >
153
/// 1、当 outTime 指定为-1时,将一直等待直到有数据需要接收;
154
/// 2、需要接收的数据的长度,由 buffer 的长度决定。
155
/// </remarks>
156
public static int RecvData ( Socket socket,byte[] buffer ,int outTime ) {
157
if ( socket == null || socket.Connected == false ) {
158
throw new ArgumentException ("参数socket 为null,或者未连接到远程计算机");
159
}
160
if ( buffer == null || buffer.Length == 0 ) {
161
throw new ArgumentException ("参数buffer 为null ,或者长度为 0");
162
}
163
buffer.Initialize ();
164
int left = buffer.Length ;
165
int curRcv = 0;
166
int flag = 0;
167
168
try {
169
while ( true ) {
170
if ( socket.Poll (outTime*1000000,SelectMode.SelectRead ) == true ) { // 已经有数据等待接收
171
curRcv = socket.Receive (buffer,curRcv,left ,SocketFlags.None );
172
left -= curRcv;
173
if ( left == 0 ) { // 数据已经全部接收
174
flag = 0;
175
break;
176
}
177
else {
178
if ( curRcv > 0 ) { // 数据已经部分接收
179
continue;
180
}
181
else { // 出现错误
182
flag = -2;
183
break;
184
}
185
}
186
}
187
else { // 超时退出
188
flag = -1;
189
break;
190
}
191
}
192
}
193
catch ( SocketException e ) {
194
Log.WriteLog ( e );
195
flag = -3;
196
}
197
return flag;
198
}
199
200
/**//// <summary>
201
/// 接收远程主机发送的数据
202
/// </summary>
203
/// <param name="socket">要接收数据且已经连接到远程主机的 socket</param>
204
/// <param name="buffer">存储接收到的数据的字符串</param>
205
/// <param name="bufferLen">待接收的数据的长度</param>
206
/// <param name="outTime">接收数据的超时时间,以秒为单位,可以精确到微秒</param>
207
/// <returns>0:接收数据成功;-1:超时;-2:接收数据出现错误;-3:接收数据时出现异常</returns>
208
/// <remarks >
209
/// 当 outTime 指定为-1时,将一直等待直到有数据需要接收;
210
/// </remarks>
211
public static int RecvData ( Socket socket,string buffer ,int bufferLen,int outTime ) {
212
if ( bufferLen <= 0 ) {
213
throw new ArgumentException ("存储待接收数据的缓冲区长度必须大于0");
214
}
215
byte[] tmp = new byte [ bufferLen ];
216
int flag = 0;
217
if ( ( flag = RecvData ( socket,tmp,outTime)) == 0) {
218
buffer = System.Text.Encoding .Default .GetString ( tmp );
219
}
220
return flag;
221
}
222
223
224
/**//// <summary>
225
/// 向远程主机发送文件
226
/// </summary>
227
/// <param name="socket" >要发送数据且已经连接到远程主机的 socket</param>
228
/// <param name="fileName">待发送的文件名称</param>
229
/// <param name="maxBufferLength">文件发送时的缓冲区大小</param>
230
/// <param name="outTime">发送缓冲区中的数据的超时时间</param>
231
/// <returns>0:发送文件成功;-1:超时;-2:发送文件出现错误;-3:发送文件出现异常;-4:读取待发送文件发生错误</returns>
232
/// <remarks >
233
/// 当 outTime 指定为-1时,将一直等待直到有数据需要发送
234
/// </remarks>
235
public static int SendFile ( Socket socket ,string fileName,int maxBufferLength,int outTime ) {
236
if ( fileName == null || maxBufferLength <= 0 ) {
237
throw new ArgumentException ("待发送的文件名称为空或发送缓冲区的大小设置不正确.");
238
}
239
240
int flag = 0;
241
try {
242
FileStream fs = new FileStream ( fileName,FileMode.Open ,FileAccess.Read );
243
long fileLen = fs.Length ; // 文件长度
244
long leftLen = fileLen; // 未读取部分
245
int readLen = 0; // 已读取部分
246
byte[] buffer = null;
247
248
if ( fileLen <= maxBufferLength ) { /**//* 文件可以一次读取*/
249
buffer = new byte [ fileLen ];
250
readLen = fs.Read (buffer,0,(int )fileLen );
251
flag = SendData( socket,buffer,outTime );
252
}
253
else { /**//* 循环读取文件,并发送 */
254
buffer = new byte[ maxBufferLength ];
255
while ( leftLen != 0 ) {
256
readLen = fs.Read (buffer,0,maxBufferLength );
257
if ( (flag = SendData( socket,buffer,outTime ) ) < 0 ) {
258
break;
259
}
260
leftLen -= readLen;
261
}
262
}
263
fs.Close ();
264
}
265
catch ( IOException e ) {
266
Log.WriteLog ( e );
267
flag = -4;
268
}
269
return flag;
270
}
271
272
/**//// <summary>
273
/// 向远程主机发送文件
274
/// </summary>
275
/// <param name="socket" >要发送数据且已经连接到远程主机的 socket</param>
276
/// <param name="fileName">待发送的文件名称</param>
277
/// <returns>0:发送文件成功;-1:超时;-2:发送文件出现错误;-3:发送文件出现异常;-4:读取待发送文件发生错误</returns>
278
public static int SendFile ( Socket socket ,string fileName ) {
279
return SendFile ( socket,fileName,2048,1 );
280
}
281
282
283
/**//// <summary>
284
/// 接收远程主机发送的文件
285
/// </summary>
286
/// <param name="socket">待接收数据且已经连接到远程主机的 socket</param>
287
/// <param name="fileName">保存接收到的数据的文件名</param>
288
/// <param name="fileLength" >待接收的文件的长度</param>
289
/// <param name="maxBufferLength">接收文件时最大的缓冲区大小</param>
290
/// <param name="outTime">接受缓冲区数据的超时时间</param>
291
/// <returns>0:接收文件成功;-1:超时;-2:接收文件出现错误;-3:接收文件出现异常;-4:写入接收文件发生错误</returns>
292
/// <remarks >
293
/// 当 outTime 指定为-1时,将一直等待直到有数据需要接收
294
/// </remarks>
295
public static int RecvFile ( Socket socket ,string fileName,long fileLength,int maxBufferLength,int outTime ) {
296
if ( fileName == null || maxBufferLength <= 0 ) {
297
throw new ArgumentException ("保存接收数据的文件名称为空或发送缓冲区的大小设置不正确.");
298
}
299
300
int flag = 0;
301
try {
302
FileStream fs = new FileStream (fileName,FileMode.Create);
303
byte [] buffer = null;
304
305
if ( fileLength <= maxBufferLength ) { /**//* 一次读取所传送的文件 */
306
buffer = new byte [ fileLength ];
307
if ( ( flag =RecvData(socket,buffer,outTime ) ) == 0 ) {
308
fs.Write ( buffer,0,(int)fileLength);
309
}
310
}
311
else { /**//* 循环读取网络数据,并写入文件 */
312
int rcvLen = maxBufferLength;
313
long leftLen = fileLength; //剩下未写入的数据
314
buffer = new byte [ rcvLen ];
315
316
while ( leftLen != 0 ) {
317
if ( ( flag =RecvData(socket,buffer,outTime ) ) < 0 ) {
318
break;
319
}
320
fs.Write (buffer,0,rcvLen );
321
leftLen -= rcvLen;
322
rcvLen = ( maxBufferLength < leftLen ) ? maxBufferLength :((int) leftLen) ;
323
}
324
}
325
fs.Close ();
326
}
327
catch ( IOException e ) {
328
Log.WriteLog ( e );
329
flag = -4;
330
}
331
return flag;
332
}
333
334
/**//// <summary>
335
/// 接收远程主机发送的文件
336
/// </summary>
337
/// <param name="socket">待接收数据且已经连接到远程主机的 socket</param>
338
/// <param name="fileName">保存接收到的数据的文件名</param>
339
/// <param name="fileLength" >待接收的文件的长度</param>
340
/// <returns>0:接收文件成功;-1:超时;-2:接收文件出现错误;-3:接收文件出现异常;-4:写入接收文件发生错误</returns>
341
public static int RecvFile ( Socket socket,string fileName,long fileLength ) {
342
return RecvFile ( socket,fileName,fileLength,2048,1);
343
}
344
}
345
}
346
在这个类中用到了一个 LogDll 的组件,主要完成发生异常或错误的时候,将信息输出到日志文件。用到了“winform 程序的配置文件——App.config ”中提到的内容,代码如下:
1
#define
DEBUG
2

3
using
System;
4
using
System.Diagnostics ;
5

6
namespace
LogDll
7

{
8
/**//// <summary>
9
/// Log : 将系统运行信息写入到日志文件
10
/// </summary>
11
/// <remarks >需要在项目的配置文件中增加如下的信息:
12
/// <configuration>
13
/// <system.diagnostics>
14
/// <switches>
15
/// <add name="MagicTraceSwitch" value="3" />
16
/// </switches>
17
/// <trace autoflush="true" indentsize="4">
18
/// <listeners>
19
/// <add name="myListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="myListener.log" />
20
/// <remove type="System.Diagnostics.DefaultTraceListener" />
21
/// </listeners>
22
/// </trace>
23
/// </system.diagnostics>
24
/// </configuration>
25
/// 其中的initializeData="myListener.log",替换为自己的日志文件名称
26
/// </remarks>
27
public class Log
28
{
29
private Log(){
30
}
31
32
public static void WriteLog ( Exception e ) {
33
Debug.WriteLine ( DateTime.Now .ToString () + ": " + e.Message +" ["+e.StackTrace +"]");
34
}
35
36
public static void WriteLog ( string message,string sourceFile ) {
37
Debug.WriteLine ( DateTime.Now .ToString () + ": " + message + " ["+sourceFile +"]");
38
}
39
40
public static void WriteLog ( string message ) {
41
Debug.WriteLine ( DateTime.Now .ToString () + ": " + message );
42
}
43
}
44
}
45

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

190

191

192

193


194

195

196

197

198

199

200


201

202

203

204

205

206

207

208

209

210

211


212


213

214

215

216

217


218

219

220

221

222

223

224


225

226

227

228

229

230

231

232

233

234

235


236


237

238

239

240

241


242

243

244

245

246

247

248


249

250

251

252

253


254

255


256

257


258

259

260

261

262

263

264

265


266

267

268

269

270

271

272


273

274

275

276

277

278


279

280

281

282

283


284

285

286

287

288

289

290

291

292

293

294

295


296


297

298

299

300

301


302

303

304

305


306

307


308

309

310

311


312

313

314

315

316


317


318

319

320

321

322

323

324

325

326

327


328

329

330

331

332

333

334


335

336

337

338

339

340

341


342

343

344

345

346


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
