在.net下进行网络编程其实也相对比较简单,因为在.net类库已经提供了大量封装好的类。在.net下网络编程比较底层的类是System.Net.Sockets.Socket类,这个类提供了丰富的方法和属性,并且还提供了异步数据传输支持。
对Socket类做一个简单的介绍,它有如下常见方法:
public Socket Accept ():为新建连接创建新的 Socket。    
public void Bind (EndPoint localEP):使 Socket 与一个本地终结点相关联。  
public void Close ():关闭 Socket 连接并释放所有关联的资源。注意这个方法有冲载方法。 
public void Connect (EndPoint remoteEP):建立与远程主机的连接。注意这个方法有重载方法。
public void Disconnect (bool reuseSocket):关闭套接字连接并是否允许重用套接字。  
public void Listen (int backlog):将 Socket 置于侦听状态。  
public int Receive (byte[] buffer):接收来自绑定的 Socket 的数据。注意这个方法有重载方法。 
public int ReceiveFrom (byte[] buffer,ref EndPoint remoteEP):接收数据报并存储源终结点。注意这个方法有重载方法。
public int Send (byte[] buffer):将数据发送到连接的 Socket。注意这个方法有重载方法。
public void SendFile (string fileName):将文件和可选数据异步发送到连接的 Socket。注意这个方法有重载方法。
public int SendTo (byte[] buffer,EndPoint remoteEP):将数据发送到特定终结点。注意这个方法有重载方法。
public void Shutdown (SocketShutdown how):禁用某 Socket 上的发送和接收。
说明:
因为在网络传输时传输的数据都是二进制形式的(表现为字节数组),所以如果要传输类似于中文这样的双字节字符就需要在传输之前用合适的编码转换成字节数组,然后接收方按照发送方的编码将接收到字节数组转换成字符串。另外,注意接收数据的时候是先声明了一个字节数组,然后将接收到的数据保存到字节数组中,这个方法有个返回值表示实际接收了多少字节数据。这是因为数组是不可变的,假如声明了一个1024字节大小的数组,而发送方仅发送1字节数据,而接收方并不直到发送方发送的数据量把整个1024字节当作发送发送的数据的话,最终会发生错误。
要实现一个服务器端的面向连接的Socket用于接收客户端的请求的话,有如下步骤:
(1)首先根据IP地址和端口号实例化一个Socket,注意端口要要大于1024并且不要使用特殊端口号,要大于1024的原因是1024以下的端口号已经被指派了,而1433、3306这样的端口号已经被用作SQL Server和MySQL的默认端口号了,若指定为这些端口号容易发生冲突。
(3)接着调用Bind()方法进行绑定,然后再调用Listen()方法用于监听,Listen()方法的参数用于指定监听的队列大小,也就是最多可容纳的等待接受的传入连接数。
(4)再调用Accept()方法,调用这个方法之后会是程序处于阻塞状态,直至有客户端连接为止。当有客户端连接,这个方法将会返回一个新的Socket,使用这个Socket与客户端进行通讯。
(5)使用Accept()方法返回的新Socket的Send()方法就可以向客户端发送数据了,还可以使用这个新Socket的Receive()接收客户端的数据。
(6)最后终止与客户端会话时,注意使用ShutDown()方法关闭Socket连接,并且使用Close()方法释放所占用的资源。

使用Socket类编写客户端的Socket程序步骤如下:
(1)首先指定远程主机和端口号实例化Socket类,注意连接的端口号一定要与服务器监听的端口号一致。
(2)接着调用Connect()方法连接远程主机。
(3)连接到远程主机之后就可以调用Send()方法向服务器发送请求了,然后可以调用Receive()方法接收服务器响应数据,注意如果是发送的类似于中文这样的双字节字符串的话,还需要按照服务器响应的字符串编码将字节数组转换成字符串。
最后终止与客户端会话时,注意使用ShutDown()方法关闭Socket连接,并且使用Close()方法释放所占用的资源。
需要特别说明的是上面是建立连接式Socket(如建立TCP协议Socket)的一般步骤,如果是建立非连接式Socket(如UDP协议Socket)就不需要进行监听端口了,直接使用ReceiveFrom()方法就能接收来自指定主机端口的数据,用SendTo()方法就能向直接主机端口发送数据。
下面一个例子来演示Socket的编程,在这个例子里服务器端可以处理多个客户端请求并响应,具体的做法是每接收到一个客户端请求就新建一个线程来与客户端通讯,主程序依然继续监听,在例子中新建的与客户端通讯的Socket类仅处理客户端的日期时间请求(为了演示,这里做了简化),根据客户端的请求的不同发送日期时间中响应信息到客户端,客户端接收到数据之后在控制台显示。
服务器端主要由两个类组成:ServerSocket类和SocketThread类,ServerSocket类用于监听客户端连接请求,SocketThread类用于接收日期时间显示请求并做出应答。
ServerSocket类代码如下(ServerSocket类和SocketThread类位于同一个类库项目中):

  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Text;
  5. namespace ServerSocket
  6. {
  7. /// <summary>
  8. /// Socket监听服务器,用于监听客户端连接请求
  9. /// 作者:周公
  10. /// 编写时间:2009-03-18
  11. /// </summary>
  12. public class ServerSocket:IDisposable
  13. {
  14. Socket listener = null;
  15. /// <summary>
  16. /// 开始监听指定端口
  17. /// </summary>
  18. public void StartListening(int port)
  19. {
  20. // Data buffer for incoming data.
  21. byte[] bytes = new Byte[1024];
  22. //以运行服务器端程序所在的机器为服务器监听客户端连接
  23. IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
  24. IPAddress ipAddress = ipHostInfo.AddressList[0];
  25. IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
  26. //创建一个TCP/IP Socket用于监听客户端连接
  27. Socket listener = new Socket(AddressFamily.InterNetwork,
  28. SocketType.Stream, ProtocolType.Tcp);
  29. try
  30. {
  31. //先绑定要监听的主机和端口
  32. listener.Bind(localEndPoint);
  33. //再开始监听,并且指定监听队列的最大长度
  34. listener.Listen(10);
  35. //开始监听连接
  36. while (true)
  37. {
  38. Console.WriteLine("等待客户端连接...");
  39. //线程将一直阻塞直到有新的客户端连接
  40. Socket handler = listener.Accept();
  41. //启用一个新的线程用于处理客户端连接
  42. //这样主线程还可以继续接受客户端连接
  43. SocketThread socketThread = new SocketThread(handler);
  44. }
  45. }
  46. catch (Exception e)
  47. {
  48. Console.WriteLine(e.ToString());
  49. }
  50. }
  51. public static int Main(String[] args)
  52. {
  53. ServerSocket server = new ServerSocket();
  54. server.StartListening(11000);
  55. return 0;
  56. }
  57. #region IDisposable 成员
  58. public void Dispose()
  59. {
  60. if (listener != null)
  61. {
  62. listener.Shutdown(SocketShutdown.Both);
  63. listener.Close();
  64. }
  65. }
  66. #endregion
  67. }
  68. }

SocketThread类代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Threading;
  5. using System.Net.Sockets;
  6. namespace ServerSocket
  7. {
  8. /// <summary>
  9. /// 用于处理客户端请求的Socket
  10. /// 作者:周公
  11. /// 编写时间:2009-03-18
  12. /// </summary>
  13. public class SocketThread:IDisposable
  14. {
  15. private Socket socket;
  16. private Thread thread;
  17. private bool isListening = false;
  18. private string text;
  19. /// <summary>
  20. /// 构造方法
  21. /// </summary>
  22. /// <param name="socket">用于处理客户端应答的Socket</param>
  23. public SocketThread(Socket socket)
  24. {
  25. this.socket = socket;
  26. isListening = true;
  27. thread = new Thread(new ThreadStart(Work));
  28. thread.Start();
  29. }
  30. public void Work()
  31. {
  32. byte[] buffer=new byte[1024];
  33. while (isListening)
  34. {
  35. int receivedLength = socket.Receive(buffer);
  36. text=System.Text.Encoding.UTF8.GetString(buffer,0,receivedLength);
  37. //<EOF>是自定义的协议,表示中止消息交流
  38. if (text.IndexOf("<EOF>") > -1)
  39. {
  40. isListening=false;
  41. socket.Send(new byte[] { 0 });
  42. }
  43. else
  44. {
  45. //Console.WriteLine("接收到的数据:" + text);
  46. //根据客户端的请求获取相应的响应信息
  47. string message = GetMessage(text);
  48. //将响应信息以字节的方式发送到客户端
  49. socket.Send(Encoding.UTF8.GetBytes(message));
  50. }
  51. }
  52. }
  53. private string GetMessage(string request)
  54. {
  55. string message = string.Empty;
  56. //Console.WriteLine("Message=" + request);
  57. switch (request)
  58. {
  59. case "date": message = "服务器日期:"+DateTime.Now.ToString("yyyy-MM-dd"); break;
  60. case "time": message ="服务器时间:"+ DateTime.Now.ToString("HH:mm:ss"); break;
  61. case "datetime": message = "服务器日期时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); break;
  62. case "year": message = "服务器年份:" + DateTime.Now.Year.ToString(); break;
  63. case "month": message = "服务器月份:" + DateTime.Now.Month.ToString(); break;
  64. case "day": message = "这是本月第" + DateTime.Now.Day.ToString()+"天"; break;
  65. default: message = "不正确的参数"; break;
  66. }
  67. return message;
  68. }
  69. #region IDisposable 成员
  70. public void Dispose()
  71. {
  72. isListening = false;
  73. if (thread != null)
  74. {
  75. if (thread.ThreadState != ThreadState.Aborted)
  76. {
  77. thread.Abort();
  78. }
  79. thread = null;
  80. }
  81. if (socket != null)
  82. {
  83. socket.Shutdown(SocketShutdown.Both);
  84. socket.Close();
  85. }
  86. }
  87. #endregion
  88. }
  89. }

客户端请求的Socket代码如下(与前面两个类位于不同的控制台项目中):

  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Text;
  5. namespace ServerSocket
  6. {
  7. /// <summary>
  8. /// 客户端请求的Socket包装类
  9. /// 作者:周公
  10. /// 编写时间:2009-03-18
  11. /// </summary>
  12. public class ClientSocket:IDisposable
  13. {
  14. private Socket sender = null;
  15. private bool isListening = false;
  16. //定义用于接收服务器响应的存储区.
  17. private byte[] bytes = new byte[1024];
  18. //用于终止Soket的消息
  19. private string shutDownMessage = "<EOF>";
  20. public ClientSocket()
  21. {
  22. try
  23. {
  24. //设置要连接的主机信息并使用11000作为监听端口.
  25. IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
  26. IPAddress ipAddress = ipHostInfo.AddressList[0];
  27. IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
  28. // 创建一个TCP/IP协议的socket连接
  29. sender = new Socket(AddressFamily.InterNetwork,
  30. SocketType.Stream, ProtocolType.Tcp);
  31. sender.Connect(remoteEP);
  32. isListening = true;
  33. }
  34. catch (Exception ex)
  35. {
  36. Console.WriteLine(ex.ToString());
  37. }
  38. }
  39. public void StartClient()
  40. {
  41. // 连接到远程主机,并捕获所有信息
  42. try
  43. {
  44. Console.WriteLine("连接到主机{0}",
  45. sender.RemoteEndPoint.ToString());
  46. OutParameters();
  47. string consoleMessage = Console.ReadLine();
  48. while (isListening&&!string.IsNullOrEmpty(consoleMessage))
  49. {
  50. consoleMessage = consoleMessage.ToLower();
  51. if (consoleMessage == "bye")
  52. {
  53. SendShutDownMessage();
  54. }
  55. else
  56. {
  57. string resultMessage=SendMessage(consoleMessage);
  58. Console.WriteLine(resultMessage);
  59. OutParameters();
  60. consoleMessage = Console.ReadLine();
  61. //Console.WriteLine("consoleMessage=" + consoleMessage);
  62. }
  63. }
  64. }
  65. catch (ArgumentNullException ane)
  66. {
  67. Console.WriteLine("参数异常 : {0}", ane.ToString());
  68. }
  69. catch (SocketException se)
  70. {
  71. Console.WriteLine("出现Socket异常: {0}", se.ToString());
  72. }
  73. catch (Exception e)
  74. {
  75. Console.WriteLine("出现了异常 : {0}", e.ToString());
  76. }
  77. }
  78. /// <summary>
  79. /// 向远程主机发送信息
  80. /// </summary>
  81. /// <param name="message">要发送的信息</param>
  82. public string SendMessage(string message)
  83. {
  84. byte[] buffer = Encoding.UTF8.GetBytes(message);
  85. sender.Send(buffer);
  86. int count=sender.Receive(bytes);
  87. return Encoding.UTF8.GetString(bytes, 0, count);
  88. }
  89. /// <summary>
  90. /// 向服务器发送关闭Socket信息,并中止与服务器的连接
  91. /// </summary>
  92. public void SendShutDownMessage()
  93. {
  94. SendMessage(shutDownMessage);
  95. Console.WriteLine("已经关闭与服务器的连接");
  96. isListening = false;
  97. Environment.Exit(0);
  98. }
  99. private void OutParameters()
  100. {
  101. Console.WriteLine("参数说明:");
  102. Console.WriteLine("获取服务器日期:date");
  103. Console.WriteLine("获取服务器时间:time");
  104. Console.WriteLine("获取服务器日期时间:datetime");
  105. Console.WriteLine("获取服务器年份:year");
  106. Console.WriteLine("获取服务器月份:month");
  107. Console.WriteLine("获取服务器天数:day");
  108. Console.WriteLine("关闭连接:bye");
  109. Console.WriteLine("请输入你要进行的操作:");
  110. }
  111. public static int Main(String[] args)
  112. {
  113. ClientSocket client = new ClientSocket();
  114. client.StartClient();
  115. return 0;
  116. }
  117. #region IDisposable 成员
  118. public void Dispose()
  119. {
  120. isListening = false;
  121. if (sender != null)
  122. {
  123. sender.Shutdown(SocketShutdown.Both);
  124. sender.Close();
  125. }
  126. }
  127. #endregion
  128. }
  129. }

上面的三个类位于两个控制台项目中ServerSocket类和SocketThread类位于同一个类库项目中,其中ClientSocket类位于另一个控制台项目中,编译之后会生成两个exe文件,运行的时候首先运行服务器端exe程序以便监听,再运行客户端exe程序。这个程序运行的效果如下:

注意,在终止程序的时候首先在客户端向服务器发送一个自定义的字符串“<EOF>”,在客户端使用命令行参数“bye”就是发送这个字符串的,这样就会正确终止服务器端响应Socket及正确关闭客户端请求的Socket,否则有可能抛出异常。
以上仅仅是演示了如何使用Socket进行编程,如果要传输文件的话,可能需要更多类似于关闭Socket的自定义字符串用以控制了。另外使用Socket来传输数据是比较高效的,但是传输控制相对来说要麻烦一点,针对网络中一些特殊场合的数据传输,可以使用特定的传输协议,在这个系列的后续文章中会继续介绍网络编程的有关知识。程序代码稍后整理之后提供下载。

目前有关在.net下进行网络编程的文章较少,而偶尔有需要进行网络编程的项目需求,所以打算研究一下.net下的网络编程,抱着交流技术的态度,整理成文章与大家分享。不过在网络编程方面,本人经验几乎没有经验,如果大家发现有不当之处,望不吝赐教。

此文中的源代码可以到:http://download.csdn.net/source/1117938下载。

转自:http://blog.csdn.net/zhoufoxcn/archive/2009/03/18/4000301.aspx

转载于:https://www.cnblogs.com/WindBlog/archive/2011/06/29/2093092.html

C#网络编程示例(note)相关推荐

  1. Muduo 网络编程示例之四:Twisted Finger

    陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice 这是<Muduo 网络编程示例>系列的第四篇文章. Muduo 全系列文章列表: http:/ ...

  2. Muduo 网络编程示例之五: 测量两台机器的网络延迟

    Muduo 网络编程示例之五: 测量两台机器的网络延迟 陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice  t.sina.com.cn/giantchen ...

  3. Muduo 网络编程示例之三:定时器

    陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice 这是<Muduo 网络编程示例>系列的第三篇文章. Muduo 全系列文章列表: http:/ ...

  4. Muduo 网络编程示例之十:socks4a 代理服务器

    Muduo 网络编程示例之十:socks4a 代理服务器 陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice  t.sina.com.cn/giantchen ...

  5. Muduo 网络编程示例之零:前言

    陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice Muduo 全系列文章列表: http://blog.csdn.net/Solstice/category ...

  6. JavaEE 网络编程示例1 UDP套接字数据报编程 == 一发一收

    鲁吼呀,胶己人! 文章目录 JavaEE & 网络编程示例1 & UDP套接字数据报编程 ==> 一发一收 1. 协议分层(回顾) 2. 套接字 Socket 2.1 UDP与T ...

  7. python服务端编程_python网络编程示例(客户端与服务端)

    client客户端 if __name__ == '__main__': import socket import os sock = socket.socket(socket.AF_INET, so ...

  8. python 网络编程_python网络编程示例(客户端与服务端)

    client客户端 if __name__ == '__main__': import socket import os sock = socket.socket(socket.AF_INET, so ...

  9. java网络编程(六)

    戳上面的蓝字关注我们哦! 精彩内容 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 java项目练习精选 网络编程示例 "实践出真知",所以在进行技术学习时, ...

最新文章

  1. python套接字socket的作用_【学习笔记】python实现的套接字socket
  2. Gulp 之图片压缩合并
  3. 金融数据信噪比的影响力又一力证
  4. Spring中ApplicationContextAware的用法
  5. SAP BTP SDK for Android 已经支持 Kotlin 了
  6. vue 实现瀑布流布局的 组件/插件总汇:vue-waterfall、vue-waterfall-easy、vue-virtual-collection、vue-grid-layout
  7. 工欲善其事,必先利其器之sublime
  8. uva 1291 - Dance Dance Revolution ( dp )
  9. 游标遍历所有数据库循环执行修改数据库的sql命令
  10. termux无法安装引导程序包_Windows 10出现升级BUG:无法保留用户个人数据
  11. 同时开多个独立窗口Visio 2003/2007版本的软件
  12. [windows] win10下的SysMain服务
  13. CAD图纸一键共享,永久轻松办公!
  14. STM32蓝牙控制LED灯开关
  15. 学习java数组的练习代码
  16. Excel如何完成多权重计算
  17. 华三H3C端口聚合与链路聚合
  18. 微信小程序支付 php后台
  19. 什么样的UI设计是高级UI设计?【萧蕊冰】
  20. AtCoder Beginner Contest 283 E - Don‘t Isolate Elements

热门文章

  1. java 程序简介
  2. 大蜘蛛序列号_Datacolor SpyderX 蓝蜘蛛 (红蜘蛛)校色仪 使用教程
  3. 网络安全之等级保护问题集
  4. vsan主机高级优化参数配置
  5. MQTT-WebSocket连接通信
  6. Java、Javascript、Javaweb三者的区别
  7. linux bond配置步骤,七种bond模式说明
  8. vSAN其实很简单-vSAN盘他之重新部署vCenter
  9. 关于“想哭”病毒,我也来两句。--转载
  10. 产品经理学习总结(2)——实用的BRD产品文档模板参考