C#Socket开发TCP详解(二)–面向连接的套接字编程
简介:
SOCKET(套件字)是支持TCP/IP 网络通信的基本操作单元。System.Net.Sockets 命名空间提供了TcpClient类、TcpListener类和UdpClient类。这些类封装了不同传输协议建立连接、操作方法的细节。
套接字有3中不同的类型:
流套接字:面向连接的TCP通信。
数据报套接字:实现无连接的UDP通信。
原始套接字:实现IP数据报通信。
socket类的构造函数:
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
对应参数的意义:
AddressFamily:网络类型,如IP版本4、IP版本6等;
SocketType :套间字类型,如流套接字,数据报套接字等;
ProtocolType :传输协议类型,如TCP、UDP等。
面向连接的套接字
在面向连接的套接字中,使用TCP来建立两个IP地址端点之间的会话。一旦设备建立的连接,就可以在设备之间进行可靠的数据传输。
为了建立面向连接的套接字,服务器和客户端需要分别进行编程。
1、建立连接
连接过程需要3个过程:服务器监听、客户端请求、连接确认。
(1)服务器编程。
在服务器中,首先创建一个本地套接字对象。如下:
//使用IPv4地址,流式socket方式,tcp协议传递数据
Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
然后,将套接字绑定到本地IP和端口上。Bind方法用于完成绑定工作。如下:
//ip地址
IPAddress ip = IPAddress.Parse(txtIP.Text);
// IPAddress ip = IPAddress.Any;
//端口号
IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));
socket.Bind(point);
将套接字与端口绑定之后,就用Listen方法等待客户端发出的尝试连接。如下:
socket.Listen(10);
Listen方法,自动将客户连接请求放到请求队列中,参数指出系统等待用户程序服务排队的连接数,超过连接数的任何客户都不能与服务器进行通信。
在Listen方法执行之后,服务器已经做好了接收任何连接的准备。这时,可用Accept方法从请求队列中获取连接。如下:
socket.Accept();
程序执行到Accept方法时会阻塞,直到收到客户端的连接请求,才继续执行下一条语句。服务器一旦接受了该客户端的连接请求,Accept方法立即返回一个与该客户端通信的信的套接字,该套接字中既包含了本机的IP地址和端口号,也包含了客户端的IP地址和端口号,然后利用此套接字与客户端进行通信了。
在实际应用场合中,为了能够与多个客户端通信,可以用一个线程监听客户端的连接请求,在该线程中循环调用Accept方法接收新的客户端连接。如下:
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
Socket socketSend;
Dictionary<string, Socket> diclist = new Dictionary<string, Socket>();
/// <summary>
/// 等待客户端的连接,并且创建与之通信用的Socket
/// </summary>
/// <param name="obj"></param>
private void Listen(object obj)
{
Socket socketWatch = obj as Socket;
while (true)
{
try
{
//等待客户端的连接,并且创建一个用于通信的Socket
socketSend = socketWatch.Accept();
//将客户端socket存到集合中
diclist.Add(socketSend.RemoteEndPoint.ToString(), socketSend);
//将客户端ip 存到下拉列表中
comboBox1.Items.Add(socketSend.RemoteEndPoint.ToString());
ShowBox(socketSend.RemoteEndPoint.ToString() + ":连接成功");
//
Thread th = new Thread(Receive);
th.IsBackground = true;
th.Start(socketSend);
}
catch
{
}
}
}
(2)客户端编程。
客户端利用Socket的connect方法向远程主机的断点发起连接请求。并将自身绑定到系统自动分配的端电上。如下:
IPAddress ip = IPAddress.Parse("192.168.10.3");
IPEndPoint point = new IPEndPoint(ip, int.Parse("9008"));
localSocket= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
localSocket.Connect(point);
程序运行后,客户端与服务器建立连接之前,系统不会执行connect语句下面的内容,而是处于阻塞状态,知道连接成功或出现异常为止。
2、发送和接收消息
客户端与服务器建立连接,客户端和服务器都可以使用Socket对象的Send和Receive方法进行通信。
(1)服务器端编程
当服务器接收客户端的连接请求成功时,Accept方法将返回包含该客户端IP地址及端口号信息的套接字。服务器可以用该套接字与客户端进行通信。
a.发送消息
Socket clientsocket = socketWatch.Accept();
//建立连接后,用Send方法向客户端发送消息
clientsocket.Send(Encoding.ASCII.GetBytes("server send Hello"));
b、接收消息
//客户端连接成功后,服务器端该接受客户端发来的额消息
byte[] buffer = new byte[1024 * 1024 * 2];
//时间接收到的有效字节数
int r = socketSend.Receive(buffer);
if (r == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer, 0, r);
ShowBox(socketSend.RemoteEndPoint + ":" + str); //输出打印消息
(2)客户端编程。
客户端可直接使用本地套接字的Send 方法向服务器发送消息,利用Receive方法接收服务器信息,例如:
a.向服务器发送消息
localSocket.Connect(point);
string str = textBox4.Text.Trim(); //添加文本
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
localSocket.Send(buffer); //发送
b.接收服务器发来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
localSocket.Receive(buffer);
Console.WriteLine("接收服务器消息:{0}",Encoding.ASCII.GetString(buffer))
3、关闭连接
注意通信完成后,必须先用Shutdown方法停止会话,然后关闭Socket实例。
localSocket.Shutdown(SocketShutdown.Both); //在套接字上既停止发送也停止接收。
localSocket.Close();
参考资料:《C#网络编程第2版》马骏主编 人民邮电出版社
示例程序及代码:
客户端界面:
服务端界面
程序地址:https://download.csdn.net/download/qq_21291397/12983392