网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket,建立网络通信连接至少要一对端口号(socket)
Socket是利用TCP/IP协议建立TCP连接。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。
Socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原义那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。
在此基础上,socket连接过程:
服务器监听:服务器端socket并不定位具体的客户端socket,而是处于等待监听状态,实时监控网络状态。
客户端请求:客户端clientSocket发送连接请求,目标是服务器的serverSocket。为此,clientSocket必须知道serverSocket的地址和端口号,进行扫描发出连接请求。
连接确认:当服务器socket监听到或者是受到客户端socket的连接请求时,服务器就响应客户端的请求,建议一个新的socket,把服务器socket发送给客户端,一旦客户端确认连接,则连接建立。
注:在连接确认阶段:服务器socket即使在和一个客户端socket建立连接后,还在处于监听状态,仍然可以接收到其他客户端的连接请求,这也是一对多产生的原因。
服务端监听:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public class Program
{
static void Main(string[] args)
{
var a = new SocketServer(8887);
a.StartListen();
}
}
public class SocketServer
{
private string _ip = string.Empty;
private int _port = 0;
private Socket _socket = null;
private byte[] buffer = new byte[1024 * 1024 * 2];
/// <summary>
/// 构造函数
/// </summary>
/// <param name="ip">监听的IP</param>
/// <param name="port">监听的端口</param>
public SocketServer(string ip, int port)
{
this._ip = ip;
this._port = port;
}
public SocketServer(int port)
{
this._ip = "127.0.0.1";
this._port = port;
}
public void StartListen()
{
try
{
//1.0 实例化套接字(IP4寻找协议,流式协议,TCP协议)
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.0 创建IP对象
IPAddress address = IPAddress.Parse(_ip);
//3.0 创建网络端口,包括ip和端口
IPEndPoint endPoint = new IPEndPoint(address, _port);
//4.0 绑定套接字
_socket.Bind(endPoint);
//5.0 设置最大连接数
_socket.Listen(int.MaxValue);
Console.WriteLine("监听{0}消息成功", _socket.LocalEndPoint.ToString());
//6.0 开始监听
Thread thread = new Thread(ListenClientConnect);
thread.Start();
}
catch (Exception ex)
{
}
}
/// <summary>
/// 监听客户端连接
/// </summary>
private void ListenClientConnect()
{
try
{
while (true)
{
//Socket创建的新连接
Socket clientSocket = _socket.Accept();
clientSocket.Send(Encoding.UTF8.GetBytes("服务端发送消息:"));
Thread thread = new Thread(ReceiveMessage);
thread.Start(clientSocket);
}
}
catch (Exception)
{
}
}
/// <summary>
/// 接收客户端消息
/// </summary>
/// <param name="socket">来自客户端的socket</param>
private void ReceiveMessage(object socket)
{
Socket clientSocket = (Socket)socket;
while (true)
{
try
{
//获取从客户端发来的数据
int length = clientSocket.Receive(buffer);
Console.WriteLine("接收客户端{0},消息{1}", clientSocket.RemoteEndPoint.ToString(), Encoding.UTF8.GetString(buffer, 0, length));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
break;
}
}
}
}
}
客户端代码:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Demo2
{
public class Program
{
private static void Main(string[] args)
{
var a = new SocketClient(8887);
a.StartClient();
}
}
public class SocketClient
{
private string _ip = string.Empty;
private int _port = 0;
private Socket _socket = null;
private byte[] buffer = new byte[1024 * 1024 * 2];
/// <summary>
/// 构造函数
/// </summary>
/// <param name="ip">连接服务器的IP</param>
/// <param name="port">连接服务器的端口</param>
public SocketClient(string ip, int port)
{
this._ip = ip;
this._port = port;
}
public SocketClient(int port)
{
this._ip = "127.0.0.1";
this._port = port;
}
/// <summary>
/// 开启服务,连接服务端
/// </summary>
public void StartClient()
{
try
{
//1.0 实例化套接字(IP4寻址地址,流式传输,TCP协议)
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.0 创建IP对象
IPAddress address = IPAddress.Parse(_ip);
//3.0 创建网络端口包括ip和端口
IPEndPoint endPoint = new IPEndPoint(address, _port);
//4.0 建立连接
_socket.Connect(endPoint);
Console.WriteLine("连接服务器成功");
//5.0 接收数据
int length = _socket.Receive(buffer);
Console.WriteLine("接收服务器{0},消息:{1}", _socket.RemoteEndPoint.ToString(), Encoding.UTF8.GetString(buffer, 0, length));
//6.0 像服务器发送消息
for (int i = 0; i < 10; i++)
{
Thread.Sleep(2000);
string sendMessage = string.Format("我是客户端发送的消息,hello world{0}", i);
_socket.Send(Encoding.UTF8.GetBytes(sendMessage));
Console.WriteLine("向服务发送的消息:{0}", sendMessage);
}
}
catch (Exception ex)
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
Console.WriteLine(ex.Message);
}
Console.WriteLine("发送消息结束");
Console.ReadKey();
}
}
}
运行结果