一、简介
人与人之间远程交流通信,需要用到电话这个工具,而电脑与电脑之间通讯,也得需要一个类似电话一样的工具来接通。
Socket·所做的就是实现电脑之间的通讯,它是一组接口,拥有相同接口的电脑可以相互传递信息。Socket是应用层与TCP/IP协议族通信的中间软件抽象层。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议
二、工作原理
先来看一张图:
1、服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。
//选择ip地址版本,套接字类型,协议类型,若是TCP则SocketType为Stream
Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //创建IP地址跟端口对象 IPAddress ip = IPAddress.Any;
//用ip跟端口号初始化得到IPEndPoint类型的实例 IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text)); socketwatch.Bind(point); ShowMsg("监听成功"); //监听队列 socketwatch.Listen(10);
//开辟新线程一直监听客户端的连接
Thread th = new Thread(Listens);
//转为后台线程
th.IsBackground = true;
//传入的socketwatch为Listen的参数
th.Start(socketwatch);
void Listens(object o) // 参数一定得是object 类型
{
Socket socketwatch = o as Socket;
while (true)
{
try
{
//等待客户端的连接,并创建一个用于通信的socket
Socket socketSend = socketwatch.Accept(); //如果把Accept()放在主线程里会一直等待卡死界面
ShowMsg(socketSend.RemoteEndPoint.ToString() + ": 连接成功");
//byte[] buffer = new byte[1024 * 1024];
//int x = socketsend.Receive(buffer);
//string str = Encoding.UTF8.GetString(buffer, 0, x);
//开辟新的后台线程一直接收客户端发来的消息
Thread th1 = new Thread(Recive);
th1.IsBackground = true;
th1.Start(socketSend);
}
catch
{}
}
2、在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。
Socket socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress iP = IPAddress.Parse(textBox1.Text); IPEndPoint point = new IPEndPoint(iP, Convert.ToInt32(textBox2.Text)); socketSend.Connect(point); ShowMsg("连接成功");
3、客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
//客户端发送数据 string str = textBox4.Text.Trim(); byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str); socketSend.Send(buffer); textBox4.Text = ""; //服务端接收数据 void Recive(object o) { Socket socketSend = o as Socket; while (true) { try { byte[] buffer = new byte[1024 * 1024]; //把输入文本传给服务端,x表示实际长度 int x = socketSend.Receive(buffer);
//当没有数据传输时,x长度为0,直接退出,否则会一直打印空值 if (x == 0) { break; } string str = Encoding.UTF8.GetString(buffer, 0, x); ShowMsg(socketSend.RemoteEndPoint + ":" + str); } catch { } } }
//服务端发送数据
string str = txtMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
txtMsg.Text = "";
//客户端接收数据,因为
void Receives()
{
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024];
//把输入文本传给服务端,x表示实际长度
int e = socketSend.Receive(buffer);
if (e == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer, 0, e);
ShowMsg(socketSend.RemoteEndPoint + ":" + str);
}
catch
{}}
三、Socket常用的方法
1、绑定:socket.BInd(IPAndPiont),服务端绑定端口号,
2、监听:socket.Listen(int x),x表示监听端口数
3、阻塞:socket.Accept(),当有客户发起连接请求时,取消线程阻塞,所以一般不会在主线程里调用Accept
4、连接:socket.Connect(),客户端在服务端准备就绪之后,发送连接请求
5、socket.Close(),关闭连接
四、注意事项
1、在winform里面创建线程有时候会被系统拦截,所以只要在winform中新建了子线程都可以在程序里加入:
//只要碰到线程问题,先把这句话加进去
Control.CheckForIllegalCrossThreadCalls = false;
2、Accpet方法一定不要用在主线程里面,会阻塞主界面