C#网络编程(一)基础篇
简介:
C#网络编程API包含在System.Net和System.Net.Sockets命名空间下,大部分网络操作都可以在其中找到相应的类来实现;包括Socket的创建和连接,网络流收发方法的封装,而且还封装了服务端类和客户端类,提供创建服务端和客户端的快速通道;
(一)Socket类
Socket类在System.Net.Sockets命名空间下,是最基本的网络操作类,其中封装了网络连接的创建和关闭,数据的收发,以及网络状态监控等一系列有用的功能;
示例(TCP):
using System;
using System.Net;
using System.Net.Sockets;
using System.Text; class Test_Tcp
{
private Socket socket;
private void Server()
{
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 绑定服务端IP和端口,客户端通过这个地址连入
server.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), ));
// 开启服务监听,参数为最大挂起队列的连接数(并发),已连接的不计
server.Listen();
// 这是一个阻塞方法,接收客户端接入,返回客户端连接Socket
socket = server.Accept();
Console.WriteLine("Local : {0}\nRemote : {1}", socket.LocalEndPoint.ToString(), socket.RemoteEndPoint.ToString());
// 数据接收:这是一个异步过程
ReceiveAsync();
// 数据发送:这是一个阻塞方法
Write();
// 关闭客户端连接Socket和服务Socket
socket.Close();
server.Close();
}
}
Server()是一个简易的基于TCP连接的服务端开启方法,使用这个方法需要用到System.Net.Sockets和System.Net两个命名空间;
服务端开启分为4步:创建Socket、绑定IP和端口Bind()、开启监听Listen()、接入客户端Accept();
其中还有两个自定义方法,ReceiveAsync()和Write(),它们分别是异步数据接收、数据发送,它们的定义在后面可以看到。
另外,Socket的Accept()接入客户端连接方法也有异步版本BeginAccept(),它的用法类似于后面的BeginReceive(),多客户端系统一般都是用这种异步接入方式,在BeginAccept方法的回调方法中,维护一个客户端连接容器;
class Test_Tcp
{
private void Client()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("127.0.0.1", );
Console.WriteLine("{0}\n{1}", socket.LocalEndPoint.ToString(), socket.RemoteEndPoint.ToString());
ReceiveAsync();
Write();
socket.Close();
}
}
Client()方法是相应的客户端开启方法,相对服务端来说代码更简单明了,而且不需绑定IP,端口也是自动分配,不过需注意Connect()方法中的IP和端口是服务端绑定的服务地址;ReceiveAysnc()、Write()和服务端中的两个方法是一样的;
using System.Text; class Test_Tcp
{
private const int BuffSize = ;
private void ReceiveAsync()
{
if (socket == null || !socket.Connected) return;
var Buff = new byte[BuffSize];
socket.BeginReceive(Buff, , BuffSize, SocketFlags.None, OnReceived, Buff);
} private void OnReceived(IAsyncResult result)
{
if (socket == null || !socket.Connected) return;
byte[] data = (byte[])result.AsyncState; int recLength = socket.EndReceive(result);
Console.WriteLine("Length = {0}", recLength); if (recLength <= ) return;
ReceiveAsync(); string msg = Encoding.Default.GetString(data, , recLength);
Console.WriteLine("Receive : {0}\n", msg);
} private void Write()
{
while (socket != null && socket.Connected)
{
string msg = Console.ReadLine();
if (msg == "exit") break;
byte[] buff = Encoding.Default.GetBytes(msg);
socket.Send(buff);
}
}
}
这3个方法是数据异步接收、数据接收回调、和聊天数据发送的方法,这里的字符串 - 字节序列转换,需要用到System.Text命名空间;
ReceiveAysnc()是开启异步数据接收方法,其中Socket.BeginReceive方法是Socket类中的异步接收方法,它需要一个字节缓冲区和一个回调方法作为参数;
OnRecieve()数据接收回调方法,在这个方法中,主要工作是开启新的异步接收方法RecieveAsync(),以及数据处理;这里的数据处理只是简单地转换为字符串,并打印到控制台,而一般在实际应用中,这里就收的数据data会用一个容器储存起来(一般是队列Queue),然后在其它地方从容器中取出数据,并进行复杂的处理;
Write()方法:在网络连接可用状态下,不断从控制台等待读取一行字符串,并将其转换为字节序列发送到socket,服务器在异步接收线程中会接收到数据,并触发回调方法OnRecieve(),控制台会看到打印的字符串;输入exit终结循环,Write()方法返回,接着关闭socket;
Socket.Send发送数据方法是一个阻塞方法,它同样也有异步版本BeginSend(),用法和BeginReceive()类似;
在实际项目应用中,数据的发送和接收会分别维护一个发送队列和接收队列,这样,应用层在调用数据发送方法时,只是把数据加入到发送队列,而不用等待发送完成,特别是数据量大的时候,等待发送的时间会影响到应用层性能;真正的数据发送用一个专门的线程不断从发送队列里面取数据并发送;数据接收也是类似维护一个接收队列。
程序入口:
class Test_Tcp
{
public void Run()
{
Console.WriteLine("Input 'c' or 's' :");
var key = Console.ReadKey();
Console.WriteLine();
if (key.Key == ConsoleKey.C)
{
Client();
}
else if (key.Key == ConsoleKey.S)
{
Server();
}
}
} class Program
{
static int Main(string[] args)
{
new Test_Tcp().Run();
return ;
}
}
(二)NetworkStream网络流
完全限定名System.Net.Sockets.NetworkStream网络流类,继承于Stream类,简单地理解就是对Socket读写网络数据的封装,用NetworkStream网络流封装Socket,可以简化数据的接收和发送;
NetworkStream的构造方法需要传入一个可用的网络Socket实例,然后就可以用流的方式替代Socket进行数据的读写;
var netStream = new NetworkStream(socket);
这里的socket必须网络连接成功(服务端连入客户端,客户端连接远程成功),才能用NetworkStream进行数据流的读写;
(三)UDP和心跳包
相比于TCP的可靠传输,UDP是一种非连接、不可靠的数据传输协议,它不需要建立连接,也就是说,服务端不需要监听Listen、接受连入Accept,而且Socket.Connected也不能用;Udp发送数据不需确定对方是否存在,网路是否可通,当然也无法确定对方是否收到(但可以手动发送返回包来通知对方),但是Udp相对Tcp的消耗也小;
Socket的构造方法第二、三个参数分别要设置为SocketType.Dgram、ProtocolType.Udp;
相比于TCP连接,UDP的客户端差别不大,但是在UDP服务端,由于没有客户端连接,数据的发送应该使用SendTo,这个方法要求传入一个客户端地址结构EndPoint表示目标终端,那么,在接收数据时,就应该保存好数据的来源地址;
那么,接收数据也应该用另一个版本ReceiveFrom,这个方法可以得到一个数据来源地址EndPoint,这时就可以保存要用到的EndPoint,这个EndPoint可以用一个容器来维护;
这两个方法在可靠连接Tcp中也可以用(但一般不这么用),另外它们都也有各自的异步版本,Begin开头的便是;
心跳包,顾名思义是一种在通信双方,定时发送一个特定的数据序列,一般3-10s,用来通知对方网络通信是正常的,一般这个数据序列短小、固定的;心跳包在Udp非连接协议中非常地必要,因为Udp没办法在没有数据接收的情况下确定网络状态;在Tcp中心跳包不是必要的,但是要求较高的项目中依然会应用心跳包;心跳超时(一般大于2倍的间隔时间),就表示网络通信失联;
C#网络编程(一)基础篇的更多相关文章
- python网络编程——socket基础篇
python的网络编程比c语言简单许多, 封装许多底层的实现细节, 方便程序员使用的同时, 也使程序员比较难了解一些底层的东西. 1 TCP/IP 要想理解socket,首先得熟悉一下TCP/IP协议 ...
- python六十七课——网络编程(基础知识了解)
网络编程: 什么是网络编程? 网络:它是一种隐形的媒介:可以将多台计算机使用(将它们连接到一起) 网络编程:将多台计算机之间可以相互通信了(做数据交互) 一旦涉及到网络编程,划分为两个方向存在,一方我 ...
- java第九节 网络编程的基础知识
/** * * 网络编程的基础知识 * 网络协议与TCP/IP * IP地址和Port(端口号) * 本地回路的IP地址:127.0.0.1 * 端口号的范围为0-65535之间,0-1023之间的端 ...
- Linux 网络协议栈开发基础篇—— 网桥br0
一.桥接的概念 简单来说,桥接就是把一台机器上的若干个网络接口"连接"起来.其结果是,其中一个网口收到的报文会被复制给其他网口并发送出去.以使得网口之间的报文能够互相转发. 交换机 ...
- (转)Android高性能编程(1)--基础篇
关于专题 本专题将深入研究Android的高性能编程方面,其中涉及到的内容会有Android内存优化,算法优化,Android的界面优化,Android指令级优化,以及Android应用内存占 ...
- Linux虚拟网络:Docker网络知识之基础篇
我们在工作中应用了docker容器化技术,服务的部署.维护和扩展都方便了很多.然而,近期在私有化部署过程中,由于不同服务器环境的复杂多变,常常遇到网络方面的问题,现象为容器服务运行正常,但宿主机.容器 ...
- 01网络编程(基础知识+OSI七层协议+TCP与UDP)
目录 01 网络编程 一.软件开发架构 1.1 CS架构 1.2 BS架构 二.网络理论前戏 2.1 简介 2.2 常见硬件 三.OSI七层协议(五层) 3.1 七层协议 3.2 五层协议 3.3 知 ...
- TCP/UDP网络编程的基础知识与基本示例(windows和Linux)
一.TCP编程的一般步骤 服务器端: 1.创建一个socket,用函数socket() 2.绑定IP地址.端口等信息到socket上,用函数bind() 3.开启监听,用函数listen() 4.接收 ...
- Linux系统编程:socket网络编程(操作篇)
一.问题思考 问1.网络通信应用在什么场合?通信的前提是什么? 答1.主要应用在不同主机进程间的互相通信,同一主机的进程也可以使用网络进行通信.通信的前提是如何标识通信进程的唯一,由于不同主机的进程极 ...
- 【Java_多线程并发编程】基础篇——synchronized关键字
1. synchronized同步锁的原理 当我们调用某对象的synchronized方法或代码块时,就获取了该对象的同步锁.例如,synchronized(obj)就获取了“obj这个对象”的同步锁 ...
随机推荐
- 翻译:WebAssembly简介:我们为什么要关心这个技术?
原文: https://tomassetti.me/introduction-to-webassembly/ WebAssembly简介:我们为什么要关心这个技术? 在对抗js的伟大战斗中有 ...
- Linux进程管理之“四大名捕”
一.四大名捕 四大名捕,最初出现于温瑞安创作的武侠小说,是朝廷中正义力量诸葛小花的四大徒弟,四人各怀绝技,分别是轻功暗器高手“无情”.内功卓越的高手“铁手”.腿功惊人的“追命”和剑法一流的“冷血”本文 ...
- NDK编程jni学习入门,声明native方法,使其作为java与c的交互接口
首先,新建工程,简历一个jave类,在其中声明native方法,关键字为native,表面这个方法是从java以为的语言实现. 其次,要实用javac编译此java文件(javac是jdk中的命令,需 ...
- SQL Serever学习12——数据库的备份和还原
公司的服务器奔溃了,事先没相应的保护措施,使得公司遭到了较大损失,为了以后不再出现类似事件,在系统中引入备份机制,使得数据库被破坏后损失降到最低. 数据的导出和导入 数据转换服务 数据转换服务DTS( ...
- mac上用 adb 命令安装Android应用
cd /Users/xxx/android-sdk-macosx/platform-tools adb install -r xxxx.apk # -r 替换当前安装包 adb uninstall ...
- MVC-AOP(面向切面编程)思想-Filter 三种注册方式
在ASP.NET MVC框架中,为我们提供了四种类型的Filter类型包括:IAuthorizationFilter.IActionFilter.IResultFilter.IExceptionFil ...
- SQL Server中的流控制语句
begin···end 该语句定义sql代码块,通常在if和while语句中使用 declare @num int ; ; begin ; print 'hello word' end if···el ...
- async和await理解代码
<1>:Async和Await的理解1 using System; using System.Collections.Generic; using System.Linq; using S ...
- 一、Java多线程基础
一.简介 1.操作系统 在早起的裸机时代,计算机非常地昂贵,而且也没有操作系统的概念,计算机从头到尾只能执行一个程序.如果程序在执行一个耗时的操作,那么在这个过程中,计算机就有大量的资源闲置在那里,这 ...
- 7、包装类、System、Math、Arrays、大数据运算
基本类型封装 基本数据类型对象包装类概述 *A:基本数据类型对象包装类概述 *a.基本类型包装类的产生 在实际程序使用中,程序界面上用户输入的数据都是以字符串类型进行存储的.而程序开发中,我们需要把字 ...