学习c#数据流相关,自然和套接字联系在一起,便于深入领悟。
上来先看看实现套接字的相关类在msdn里面的结构体系位置:
定义:
首先来自百度百科里面是这样定义的。套接字:多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。
下面是自己理解。套接字:一个连接的两个端点。也可以这样理解,套接字是用来通信的或者说是用来数据交流的,既然要通信肯定有两个端点,就像一个线段
的两个端点一样,也就像从我家到你家一样,这条线段的两个端点,就俗称做所谓的套接字。
分类:
其中的一种分类是这样的:流式套接字、数据包套接字、原始套接字。这是按照构造函数中的第二个参数来分类的。
但是我觉得这样的分类不是很好,我更喜欢下面的分类方式:面向连接的套接字、无连接的套接字。这里是按照第三个参数来分类的。
其实这两种分类方式都是根据Socket类的构造函数的参数来分类的。
public Socket(
AddressFamilyaddressFamily, //网络类型
SocketTypesocketType, //套接字类型
ProtocolTypeprotocolType); //使用的协议
测试用例代码:
1、面向连接套接字实现:
通信原理图示:
源代码:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
//服务器端代码
namespace tcpserver
{
class server
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread] //指定应用程序运行在单线程模式
static void Main(string[] args)
{
//
// TODO: 在此处添加代码以启动应用程序
//
int recv;//用于表示客户端发送的信息长度
byte[] data = new byte[1024];//用于缓存客户端所发送的信息,通过socket传递的信息必须为字节数组
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);//本机预使用的IP和端口
//申请套接字用来传递信息
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newsock.Bind(ipep);//绑定
newsock.Listen(10);//监听
//键盘提示用户输入
Console.WriteLine("waiting for a client");
Socket client = newsock.Accept();//当有可用的客户端连接尝试时执行,并返回一个新的socket,用于与客户端之间的通信
IPEndPoint clientip = (IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("connect with client:" + clientip.Address + " at port:" + clientip.Port);
string welcome = "welcome here!";
//发送信息
data = Encoding.ASCII.GetBytes(welcome);
client.Send(data, data.Length, SocketFlags.None);
while (true)
{//用死循环来不断的从客户端获取信息
data = new byte[1024];
recv = client.Receive(data);
Console.WriteLine("recv=" + recv);
if (recv == 0)//当信息长度为0,说明客户端连接断开
break;
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
client.Send(data, recv, SocketFlags.None);
}
Console.WriteLine("Disconnected from" + clientip.Address);
//结束通信,关闭
client.Close();
newsock.Close();
}
}
}
///
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
//客户端代码
namespace tcpclient
{
/// <summary>
/// Class1 的摘要说明。
/// </summary>
class client
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
//创建一个套接字,来进程服务器直接的通信
Socket newclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//从键盘接受参数,服务器ip和端口号
Console.Write("please input the server ip:");
string ipadd = Console.ReadLine();
Console.WriteLine();
Console.Write("please input the server port:");
int port = Convert.ToInt32(Console.ReadLine());
//将网络端口表示成ip地址和端口
IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ipadd), port);//服务器的IP和端口
try
{
//因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。不需要监听。
//用刚才创建的套接字来连接从键盘接受到得ip和端口指定的网络端口。
newclient.Connect(ie);
}
catch (SocketException e)
{
Console.WriteLine("unable to connect to server");
Console.WriteLine(e.ToString());
return;
}
//套接字接受数据并将数据存入数据缓冲区
byte[] data = new byte[1024];
int recv = newclient.Receive(data);
string stringdata = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(stringdata);
while (true)
{
string input = Console.ReadLine();
if (input == "exit")
break;
//通过套接字来发送键盘接受的数据到服务器
newclient.Send(Encoding.ASCII.GetBytes(input));
data = new byte[1024];
recv = newclient.Receive(data);
stringdata = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(stringdata);
}
Console.WriteLine("disconnect from sercer");
//断开连接
newclient.Shutdown(SocketShutdown.Both);
newclient.Close();
}
}
}
2、无连接套接字(未测试):
通信原理图示:
源代码 :
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
//服务器端
namespace SimpleUdpSrvr
{
class Program
{
static void Main(string[] args)
{
int recv;
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);//定义一网络端点
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);//定义一个Socket
newsock.Bind(ipep);//Socket与本地的一个终结点相关联
Console.WriteLine("Waiting for a client..");
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.GetBytes(data,0,recv));
string welcome = "Welcome to my test server!";
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);
}
}
}
}
/
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
//客户端
namespace SimpleUdpClient
{
class Program
{
static void Main(string[] args)
{
byte[] data = new byte[1024];//定义一个数组用来做数据的缓冲区
string input, stringData;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
string welcome = "Hello,are you there?";
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 == "text")//结束标记
{
break;
}
server.SendTo(Encoding.ASCII.GetBytes(input), Remote);//将数据发送到指定的终结点Remote
data = new byte[1024];
recv = server.ReceiveFrom(data, ref Remote);//从Remote接受数据
stringData = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(stringData);
}
Console.WriteLine("Stopping client");
server.Close();
}
}
}
希望对朋友有所帮助。