C#Socket编程

2023-11-03

Microsoft.Net Framework为应用程序访问Internet提供了分层的、可扩展的以及受管辖的网络服务,其名字空间System.Net和System.Net.Sockets包含丰富的类可以开发多种网络应用程序。.Net类采用的分层结构允许应用程序在不同的控制级别上访问网络,开发人员可以根据需要选择针对不同的级别编制程序,这些级别几乎囊括了Internet的所有需要--从socket套接字到普通的请求/响应,更重要的是,这种分层是可以扩展的,能够适应Internet不断扩展的需要。

抛开ISO/OSI模型的7层构架,单从TCP/IP模型上的逻辑层面上看,.Net类可以视为包含3个层次:请求/响应层、应用协议层、传输层。WebReqeust和WebResponse 代表了请求/响应层,支持Http、Tcp和Udp的类组成了应用协议层,而Socket类处于传输层。可以如下示意:


可见,传输层位于这个结构的最底层,当其上面的应用协议层和请求/响应层不能满足应用程序的特殊需要时,就需要使用这一层进行Socket套接字编程。

而在.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 s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


若要使用 UDP 而不是 TCP,需要更改协议类型,如下面的示例所示:

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);


一旦创建 Socket,在客户端,你将可以通过Connect方法连接到指定的服务器,并通过Send/SendTo方法向远程服务器发送数据,而后可以通过Receive/ReceiveFrom从服务端接收数据;而在服务器端,你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联,并通过Listen方法侦听该接口上的请求,当侦听到用户端的连接时,调用Accept完成连接的操作,创建新的Socket以处理传入的连接请求。使用完 Socket 后,记住使用 Shutdown 方法禁用 Socket,并使用 Close 方法关闭 Socket。其间用到的方法/函数有:

Socket.Connect方法:建立到远程设备的连接
public void Connect(EndPoint remoteEP)(有重载方法)
Socket.Send 方法:从数据中的指示位置开始将数据发送到连接的 Socket。
public int Send(byte[], int, SocketFlags);(有重载方法)
Socket.SendTo 方法 将数据发送到特定终结点。
public int SendTo(byte[], EndPoint);(有重载方法)
Socket.Receive方法:将数据从连接的 Socket 接收到接收缓冲区的特定位置。
public int Receive(byte[],int,SocketFlags);
Socket.ReceiveFrom方法:接收数据缓冲区中特定位置的数据并存储终结点。
public int ReceiveFrom(byte[], int, SocketFlags, ref EndPoint);
Socket.Bind 方法:使 Socket 与一个本地终结点相关联:
public void Bind( EndPoint localEP );
Socket.Listen方法:将 Socket 置于侦听状态。
public void Listen( int backlog );
Socket.Accept方法:创建新的 Socket 以处理传入的连接请求。
public Socket Accept();
Socket.Shutdown方法:禁用某 Socket 上的发送和接收
public void Shutdown( SocketShutdown how );
Socket.Close方法:强制 Socket 连接关闭
public void Close();


可以看出,以上许多方法包含EndPoint类型的参数,在Internet中,TCP/IP 使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备;端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点,在 .NET 框架中正是由 EndPoint 类表示这个终结点,它提供表示网络资源或服务的抽象,用以标志网络地址等信息。.Net同时也为每个受支持的地址族定义了 EndPoint 的子代;对于 IP 地址族,该类为 IPEndPoint。IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息,通过组合服务的主机IP地址和端口号,IPEndPoint 类形成到服务的连接点。

用到IPEndPoint类的时候就不可避免地涉及到计算机IP地址,.Net中有两种类可以得到IP地址实例:

IPAddress类:IPAddress 类包含计算机在 IP 网络上的地址。其Parse方法可将 IP 地址字符串转换为 IPAddress 实例。下面的语句创建一个 IPAddress 实例:

IPAddress myIP = IPAddress.Parse("192.168.1.2");


Dns 类:向使用 TCP/IP Internet 服务的应用程序提供域名服务。其Resolve 方法查询 DNS 服务器以将用户友好的域名(如"host.contoso.com")映射到数字形式的 Internet 地址(如 192.168.1.1)。Resolve方法 返回一个 IPHostEnty 实例,该实例包含所请求名称的地址和别名的列表。大多数情况下,可以使用 AddressList 数组中返回的第一个地址。下面的代码获取一个 IPAddress 实例,该实例包含服务器 host.contoso.com 的 IP 地址。

IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];


你也可以使用GetHostName方法得到IPHostEntry实例:

IPHosntEntry hostInfo=Dns.GetHostByName("host.contoso.com")


在使用以上方法时,你将可能需要处理以下几种异常:

SocketException异常:访问Socket时操作系统发生错误引发

ArgumentNullException异常:参数为空引用引发

ObjectDisposedException异常:Socket已经关闭引发

在掌握上面得知识后,下面的代码将该服务器主机( host.contoso.com的 IP 地址与端口号组合,以便为连接创建远程终结点:

IPEndPoint ipe = new IPEndPoint(ipAddress,11000);


确定了远程设备的地址并选择了用于连接的端口后,应用程序可以尝试建立与远程设备的连接。下面的示例使用现有的 IPEndPoint 实例与远程设备连接,并捕获可能引发的异常:

try {
s.Connect(ipe);//尝试连接
}
//处理参数为空引用异常
catch(ArgumentNullException ae) {
Console.WriteLine("ArgumentNullException : {0}", ae.ToString());
}
//处理操作系统异常
catch(SocketException se) {
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch(Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}


需要知道的是:Socket 类支持两种基本模式:同步和异步。其区别在于:在同步模式中,对执行网络操作的函数(如 Send 和 Receive)的调用一直等到操作完成后才将控制返回给调用程序。在异步模式中,这些调用立即返回。

另外,很多时候,Socket编程视情况不同需要在客户端和服务器端分别予以实现,在客户端编制应用程序向服务端指定端口发送请求,同时编制服务端应用程序处理该请求,这个过程在上面的阐述中已经提及;当然,并非所有的Socket编程都需要你严格编写这两端程序;视应用情况不同,你可以在客户端构造出请求字符串,服务器相应端口捕获这个请求,交由其公用服务程序进行处理。以下事例语句中的字符串就向远程主机提出页面请求:

string Get = "GET / HTTP/1.1/r/nHost: " + server + "/r/nConnection: Close/r/n/r/n";


远程主机指定端口接受到这一请求后,就可利用其公用服务程序进行处理而不需要另行编制服务器端应用程序。

综合运用以上阐述的使用Visual C#进行Socket网络程序开发的知识,下面的程序段完整地实现了Web页面下载功能。用户只需在窗体上输入远程主机名(Dns 主机名或以点分隔的四部分表示法格式的 IP 地址)和预保存的本地文件名,并利用专门提供Http服务的80端口,就可以获取远程主机页面并保存在本地机指定文件中。如果保存格式是.htm格式,你就可以在Internet浏览器中打开该页面。适当添加代码,你甚至可以实现一个简单的浏览器程序。


实现此功能的主要源代码如下:

//"开始"按钮事件
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();
}
}


程序在WindowsXP中文版、.Net Frameworkd 中文正式版、Visual Studio.Net中文正式版下调试通过

 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#Socket编程 的相关文章

  • 在 C++ 中重用异常处理代码

    我有这两个函数 具有重复的异常处理 其唯一目的是显示错误消息 void func1 noexcept try do task do another task catch const std out of range e show msg O
  • 我可以处理 XAML 中引发的异常吗?

    在我的 XAML 中 我通过绑定到 GetAll 属性来获取所有客户
  • Linux 中不使用 C++ 的 C 异常处理

    Linux 是否提供了 C 语言的异常处理而不求助于 C 或者 实现此类异常处理的最佳方法是什么 目标是避免检查每个调用的函数的返回码 而是执行类似于 C 的线程安全且易于移植的操作 您可以通过为其编写信号处理程序来处理信号 GNU 记录的
  • 如何从 obj-c / ios 中的堆栈跟踪获取源代码行

    I use NSSetUncaughtExceptionHandler将堆栈跟踪打印到 iPhone 中的本地文件 该文件将在下次应用程序启动时发送到我们的服务器 然后我可以检查异常数据并修复错误 在某些崩溃中 我有模块名称和引发异常的函数
  • Windows批处理支持异常处理吗?

    Windows批处理编程支持异常处理吗 如果没有 是否有任何方法可以有效地模拟批处理文件中的异常处理 我希望能够在批处理脚本中的任何 CALL 级别的任何位置 抛出异常 并重复弹出 CALL 堆栈 直到找到活动的 TRY 块 然后 CATC
  • 复制到其他计算机时无法在 WcfTestClient 中添加服务

    我想在另一台计算机上运行 WcfTestClient VS2012 中包含的一个 而不安装 VS2012 这可能吗 在我已经安装了 NET 4 5 的机器上 但是当我尝试添加 Web 服务时 它给了我以下堆栈跟踪 Exception Tex
  • 最佳实践:从属性中抛出异常

    什么时候适合从属性 getter 或 setter 中抛出异常 什么时候不合适呢 为什么 关于这个主题的外部文档的链接会很有帮助 谷歌搜索结果出奇的少 Microsoft 在以下位置提供了有关如何设计属性的建议 http msdn micr
  • 我们什么时候应该在方法中抛出异常或捕获异常?

    我一直在阅读有关异常的更多内容 但我不确定在什么情况下我们应该抛出一个方法 public void fxml throws IOException method body here 或捕获方法内的异常 public void fxml FX
  • Python Tornado 中的异常处理

    我正在尝试处理发生的异常AsyncClient fetch这样 from tornado httpclient import AsyncHTTPClient from tornado httpclient import HTTPReques
  • ScrollView 只能承载一个直接子级,但它只有一个

    每当我开始活动时 我都会收到此错误 这是完整的堆栈跟踪 Process com example PID 28799 java lang RuntimeException Unable to start activity ComponentI
  • 如何在 C# 中捕获等待的异步方法的异常?

    我基本上想知道在 C 中我应该如何捕获通过等待的异步方法的异常await关键词 例如 考虑以下小控制台程序 其中最重要的是包含一个名为AwaitSync AwaitSync calls TestAsync 它返回一个任务 执行时会抛出异常
  • Android ListView addHeaderView() XML 中定义的预定义视图出现 nullPointerException

    尝试使用addHeaderView and addFooterView for a ListView 如果我尝试使用在 XML 中为页眉或页脚预定义的视图 则会出现空指针异常 但是 如果我使用代码动态创建一个视图 它工作得很好 This d
  • 如何将exe异常路由回VB6应用程序?

    我有一个 vb6 应用程序 它将调用 mencoder exe 它是 mplayer 的一部分 用于将某些文件转换为 flv 格式 每当我尝试转换这个 opendivx 文件时 我都会从 mencoder 收到这个奇怪的未处理异常问题 目前
  • 捕获 SQLAlchemy 异常

    我可以使用什么捕获 SQLAlechmy 异常的上层异常 gt gt gt from sqlalchemy import exc gt gt gt dir exc ArgumentError CircularDependencyError
  • PHP:如何检查 Guzzle 4 中的超时异常?

    如果请求期间发生错误 Guzzle 会引发异常 不幸的是 似乎没有特定于超时的错误 这对我来说很重要 因为我知道这些错误偶尔会发生 我想重试相应的请求 并且需要能够判断错误是否是由于超时而发生的 来自docs http docs guzzl
  • PHP MVC 应用程序中哪里可以捕获异常?

    我有一个中小型 PHP 应用程序 用于练习 OOP 和 MVC 技能 我有初始化 引导程序调用的文件Router谁打电话控制器 gt 服务层 gt 存储库 数据库 然后将变量发送回视图层 所有依赖项均由 DiC IOC 处理 我创建抽象类
  • 如何为未捕获的异常处理程序编写单元测试

    我有一个函数可以捕获uncaught例外情况 如下 有没有办法编写一个单元测试来执行uncaught exception handler 功能正常 但测试正常退出 import logging def config logger logge
  • Spring Integration中的异常:如何记录但不拦截

    假设我有一个基本的 Spring 集成流程 例如
  • 为什么密码错误会导致“填充无效且无法删除”?

    我需要一些简单的字符串加密 所以我编写了以下代码 有很多 灵感 来自here http www codeproject com KB security DotNetCrypto aspx create and initialize a cr
  • 捕获特定的 WebException (550)

    假设我创建并执行一个System Net FtpWebRequest 我可以用catch WebException ex 捕获此请求引发的任何与 Web 相关的异常 但是 如果我有一些逻辑只想在由于以下原因引发异常时执行 550 file

随机推荐

  • 关系数据库

    关系 关系 描述实现事物的一张二维表 外码 关系A中的一组非主属性 其与关系B的主属性对应 则称关系A这组属性为A的外码 关系A为参照关系 关系B为被参照关系 关系完整性 实体完整性 主属性不能取空值 主属性应具有唯一区分性 参照完整性 外
  • 区块链入门系列之共识算法

    区块链入门系列文章 区块链基本概念和名词解释 P2P 共识算法 梅克尔 帕特里夏树 从零开始搭建区块链 这里写自定义目录标题 区块链入门系列文章 前言 POW POS PBFT Raft 其他共识算法 前言 前文已经说过 区块链从本质上来说
  • task1

    Task1 伯努利模型 P X 1 p P X 0 1 p 三要素 1 极大似然估计 模型 伯努利模型 策略 经验风险最小化 极大似然估计 等价于当模型是条件概率分布 损失函数是对数损失函数时的经验风险最小化 算法 极大化似然 P X p
  • MySQL的存储过程

    存储过程是组为了完成特定功能的SQL语句集合 存储过程在使用过程中是将常用或者复杂的工作预先使用SQL语句写好并用一个指定的名称存储起来 这个过程经编译和优化后存储在数据库服务器中 当需要使用该存储过程时 只需要调用它即可 存储过程在执行上
  • linux多节点zookeeper(不限于zookeeper)批量调起(举例,问题排查)

    小脚本 废话不多说直接来 bin bash flag 1 DfsOrAll 2 启动zookeeper 这里 hadoop01 hadoop02 hadoop03 都是节点别名 取代ip地址 可在 etc hosts配置 for i in
  • 翻转的卡片

    前言 第二篇 CodingStartup起码课 的视频练习 这几天都在看他的视频 然后跟着做出效果来 HTML CSS 制作翻牌效果 效果图 要点 使用 position 设置 2 个卡片重叠 正为 正面 反为 背面 transform r
  • pandas统计分析(下)——数据格式化、分组统计

    数据格式化 在数据处理以后需要对数据进行格式化 以增加数据的可读性 设置小数位数 主要使用round函数实现四舍五入 decimals参数用于设置保留小数的位数 round decimals 0 args kwargs decimals 每
  • android对webkit做了哪些封装,lAndroidwebkit简介及开发遇到的一些问题.doc

    lAndroidwebkit简介及开发遇到的一些问题 Android webkit简介 张立鹏 M厂开发五部目录 1 webkit架构2 2 Application3 2 1 WebViewClient里面几个重要方法3 2 2 WebCh
  • sql net message from client

    sql net message from client 2011 05 09 15 18 17 分类 等待事件 标签 字号大中小 订阅 sql net message from client大部分情况下对于数据库来说是空闲等待事件 表示数据
  • [Gradle中文教程系列]-跟我学Gradle-5.3:依赖-管理依赖的版本(传递(transitive)\排除(exclude)\强制(force)\动态版本(+))

    http blog csdn net pkaq article details 53906668
  • 抓包查看http + json 中的 json信息

    一 抓包查看 抓包中过滤http报文 因为json信息在http response中 点击 http 1 1 200 OK 报文 查看这个报文中的 http gt hypertext transfer protocol gt line ba
  • AndroidStudio编译调试aosp11R 的Launcher3

    1 下载aosp并编译 2 下载Launcher3 可以直接使用aosp中的 也可以使用git单独下载 git clone https android review googlesource com platform packages ap
  • 模式分类识别

    模式分类识别 BP神经网络多特征分类预测 Matlab完整程序 目录 模式分类识别 BP神经网络多特征分类预测 Matlab完整程序 分类结果 基本介绍 程序设计 参考资料 分类结果 基本介绍
  • Linux中的用户登录和管理指令

    关机 重启指令 shutdown h now 立刻进行关机 shutdown h 1 1分钟之后自动关机 同时该指令和shutdown 作用一致 shutdown r now 现在重新启动计算机 r代表reboot halt 立即关机 re
  • js怎么实现数组里的数据相加_JS怎么对数组内元素进行求和

    JS数组内元素求和 我们可以使用reduce 方法查找或计算数字数组的总和 该reduce 方法对数组的每个成员执行指定的reducer函数 从而生成单个输出值 下面我们就结合具体的代码示例 给大家介绍JS数组内元素求和的实现方法 代码示例
  • 文章生成器-原创文章生成器

    在网络营销领域 优质文章是吸引新客户和保留老客户的重要工具 然而 生成高质量且符合SEO优化的文章并不是一件容易的事情 这就是为什么网站文章生成器如今备受欢迎的原因 而在众多的文章生成工具中 147GPT批量生成文章软件是一款非常出色的文章
  • ACM金牌学长,算法竞赛经验分享

    大家好 我是编程熊 不少读者问我 本科打算法竞赛 你如何训练的呀 有什么经验么 于是小熊写一篇ACM算法竞赛入门和进阶指南 分享一下经验和学习方法 也许你可能不参加算法竞赛 但知道厉害的人如何学习 训练 一步步变强 也是可以借鉴和学习的 如
  • qt中comobox下拉框的样式

    参考博客 https blog csdn net li235456789 article details 50915842 1 实现效果如下 1 实现代码如下 放在样式表中实现 QComboBox drop down subcontrol
  • Android数据库安全解决方案,使用SQLCipher进行加解密

    转载请注明出处 http blog csdn net guolin blog article details 11952409 我们都知道 Android系统内置了SQLite数据库 并且提供了一整套的API用于对数据库进行增删改查操作 数
  • C#Socket编程

    Microsoft Net Framework为应用程序访问Internet提供了分层的 可扩展的以及受管辖的网络服务 其名字空间System Net和System Net Sockets包含丰富的类可以开发多种网络应用程序 Net类采用的