什么是socket?
所谓socket通常也称作"套接字",用于描述IP地址bai和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
socket连接过程:
socket分为服务端及客户端,这里我们用serverSocket及clientSocket分别表示
服务器监听:服务器端socket并不主动指定的客户端socket,而是处于等待监听状态,实时监控网络状态。
客户端请求:客户端clientSocket发送连接请求,目标是服务器的serverSocket。所以clientSocket必须知道serverSocket的ip及端口号
连接确认:当服务器socket监听到或者是受到客户端socket的连接请求时,服务器就响应客户端的请求,建议一个新的socket,把服务器socket发送给客户端,一旦客户端确认连接,则连接建立。
下图简单说明链接过程:
具体可以参考简易代码(这里源码已放入“墨水直达”公众号,回复socket源码即可):
源码为wpf,因为项目源码不好拆分,且不好打包,所以建了个实例,这里看不太明白的可以下载源码好好研究下
//服务端
Thread threadWatch = null;
Socket Mysocket = null;
ListBox ClientListboxs = null;
//接受缓存
byte[] arrMsgRec = new byte[1024 * 1024 * 2];
Socket policy = null;
Dictionary<string, Socket> SoketList = new Dictionary<string, Socket>();
Thread threadRece = null;
private void StartSocket()
{
//创建监听套接字
Mysocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获取ip对象
IPAddress address = IPAddress.Parse("192.168.3.57");
//创建IP和端口
IPEndPoint endpoint = new IPEndPoint(address, int.Parse("4502"));
Mysocket.Bind(endpoint);//绑定EndPoint对像
//监听队列长度
Mysocket.Listen(10);
threadWatch = new Thread(WatchConnection);
threadWatch.IsBackground = true;
threadWatch.Start();
}
// 监听新客户端请求
private void WatchConnection()
{
showMessage("等待客户连接");
while (true)
{
policy = Mysocket.Accept();
Socket policynew = policy;
showMessage("连接成功");
ListBox ClientListbox = ClientListboxs;
ClientListbox.Dispatcher.Invoke(new Action(() => { ClientListbox.Items.Add(policynew.RemoteEndPoint.ToString()); }));
SoketList.Add(policynew.RemoteEndPoint.ToString(), policy);//为新建连接创建新的socket
if (threadRece == null)
{
threadRece = new Thread(Rece);
threadRece.IsBackground = true;
threadRece.Start();
}
}
}
这个线程是一直存在的,主要的任务就是监听是否有Client与Server端进行连接,如果连接成功则会另开一个线程”Rece”。在该线程中则主要是得到字符数据的处理,包括接受数据以及发送数据。
private void Rece()
{
while (true)
{
try
{
int strlong = policy.Receive(arrMsgRec);
byte[] message = arrMsgRec;
byte[] lin = arrMsgRec.Skip(2).Take(strlong - 4).ToArray();
string strMsgRec = System.Text.Encoding.UTF8.GetString(lin, 0, strlong - 4);//实际转换的字节长度为内容长度
showMessage(strMsgRec);
}
catch (Exception)
{
}
}
}
private void showMessage(string msg)
{
Action action = () => MsgContent.AppendText(msg + "\r\n");
if (System.Threading.Thread.CurrentThread !=
MsgContent.Dispatcher.Thread)
{
MsgContent.Dispatcher.Invoke
(System.Windows.Threading.DispatcherPriority.Normal,
action);
}
else
{
action();
}
}
下面是向客户端发送数据
private void send(object sender, RoutedEventArgs e)
{
senddate = System.DateTime.Now;
var TELH = (char)0x02 + (char)0x30;//头部(无需照搬,测试用的)
var TELF = (char)0x5F + (char)0x03;//尾部(无需照搬,测试用的)
var Content = MsgContext.Text;
var msg = TELH + Content + TELF;
byte[] btMsg = System.Text.Encoding.UTF8.GetBytes(msg);
policy.Send(btMsg);
showMessage("发送:" + MsgContext.Text);
}
这里需要注意:其实在TCP/IP传输的数据都应该是以字节为单位的。比如说传送50个double类型的数据就是传送400个字节的数组
//客户端
Socket Mysocket = null;
byte[] arrMsgRec = new byte[1024 * 1024 * 2];
public void client()
{
Mysocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获取ip对象
IPAddress address = IPAddress.Parse("192.168.3.57");
//创建IP和端口
IPEndPoint endpoint = new IPEndPoint(address, int.Parse("4502"));
Mysocket.Connect(endpoint);
Thread threadWatch = new Thread(ReceiveMsg);
//threadWatch.IsBackground = true;
threadWatch.Start();
}
从服务端源码可以看到消息的组成由头部(两字节)+内容+尾部(两字节)组成,所以这里取内容的话跳过头部取总长度-4的部分就好了
public void ReceiveMsg()
{
while (true)
{
int strlong = Mysocket.Receive(arrMsgRec);
byte[] message = arrMsgRec;
byte[] lin = arrMsgRec.Skip(2).Take(strlong - 4).ToArray();
string strMsgRec = System.Text.Encoding.UTF8.GetString(lin, 0, strlong - 4);//实际转换的字节长度为内容长度
showMessage(strMsgRec);
}
}
//发送
public void Sends()
{
var TELH = (char)0x02 + (char)0x30;//头部
var TELF = (char)0x5F + (char)0x03;//尾部
var Content = MsgSend.Text;
var msg = TELH + Content + TELF;
byte[] btMsg = System.Text.Encoding.UTF8.GetBytes(msg);
Mysocket.Send(btMsg);
showMessage("发送:" + MsgSend.Text);
}
将数据显示在控件上
private void showMessage(string msg)
{
Action action = () => MsgContent.AppendText(msg + "\r\n");
if (System.Threading.Thread.CurrentThread !=
MsgContent.Dispatcher.Thread)
{
MsgContent.Dispatcher.Invoke
(System.Windows.Threading.DispatcherPriority.Normal,
action);
}
else
{
action();
}
}
这里,简单的一个socket通讯就完成了,效果如下:
socket的实际用处有很多,这里我主要用于程序和设备进行通讯,像qq就是用socket通信的,浏览器和服务器也是用socket进行通信的,只是传输的是以http协议的http报文, 有兴趣的朋友可以自己研究下
这里推荐一篇比价详细的博文http://www.jytek.com/seesharpsocket
有兴趣的可以关注“墨水直达”,里面有许多免费的编程资料可以领取哦~