黑马程序员---.NET高级之网络套接字(Socket)编程
1.什么是套接字Socket?
所谓socket通常也称作"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
Socket有两种类型:
–流式Socket(STREAM):
是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低;
是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低;
–数据报式Socket(DATAGRAM):
是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.
是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.
2.Socket的常用方法
Socket (): 创建一个套接字Socket
Bind(): 绑定一个本地的IP和端口号(IPEndPoint)
Listen(): 让Socket侦听传入的连接尝试,并指定侦听队列容量
Connect(): 初始化与另一个Socket的连接
Accept(): 接收连接并返回一个新的socket
Send(): 输出数据到Socket
Receive(): 从Socket中读取数据
Close(): 关闭Socket (销毁连接)
3.Socket的通讯过程
-创建Socket()一个Socket
-绑定Bind()到一个IP地址和一个端口上
-开启Listen()侦听,等待接受连接Connect()
-接到Accept()连接请求后,Accept()产生一个新的socket(端口大于1024)与客户端建立连接并利用Send()/Receive()进行通讯,原侦听socket继续侦听新的连接
-通讯结束,用Close()关闭Socket,销毁连接
如下通讯示意图:
套接字Socket通讯示例代码如下:
服务器端负责监听的代码
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace tcpserver {
///<summary>
/// Class1 的摘要说明。
///</summary>
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)
{
// TODO: 在此处添加代码以启动应用程序
byte [] data = new byte [ 1024 ];
Socket newclient = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
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());
IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ipadd),port); // 服务器的IP和端口
try
{
// 因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。不需要监听。
newclient.Connect(ie);
}
catch (SocketException e)
{
Console.WriteLine( " unable to connect to server " );
Console.WriteLine(e.ToString());
return ;
}
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();
}
}
}