在说到Socket的TCP通信之前,先给大家讲述整个网络流程:TCP/IP协议分层:网络接口层、网络层、传输层、应用层,而Socket进行通信是应用层与传输层进行通信。
而应用层向传输层进行信息传递通信的时候,TCP会遇多个客户端同时向一个服务端发出请求,并且该请求信息均通过一个端口来进行传输。为了区别不同的客户端,计算机应用程序与TCP/IP协议交互提供了Socket(套接字)的接口,每一个套接字对应于一组IP+PORT,这样我们就能区分不同的客户端了。
1.Socket的通讯原理
服务端:
(1)建立服务器端的Socket即(ServerSocket)
(2)确定服务器端的IP以及传输端口,并将IP以及ServerSocket进行实例化,通过.bind进行绑定IP以及端口
(3)然后创建一个线程,服务器端开始监听客户端的信息。
(4)当有一个客户端进行连接时,创建一个与客户端进行连接通信的Socket,即ClientSocket,通过ServerSocket返回的是该连接的ClientSocket的IP以及端口。
(5)将上一步连接的Client的Socket进行保存。
(6)接收到客户端的信息以及给客户端发送信息比较类似。
代码如下:
前2步操作,创建ServerSocket,并进行绑定。
//申请一个socket用来监听
int port = 50000;//确定一个端口
string ipofserver = "192.168.0.5";//确定一个IP地址
IPAddress serverip = IPAddress.Parse(ipofserver);//将IP地址字符串转换为IPAddress实例
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//使用指定的地址簇协议、套接字类型和通信协议
IPEndPoint endPoint = new IPEndPoint(serverip, port);//用指定的ip和端口号初始化IPendPint实例,将服务器端绑定到一个地址和一个端口上
//建立通信
ServerSocket.Bind(endPoint);//绑定IP地址以及端口号
ServerSocket.Listen(10);//设定可以监听10个
第三步操作,创建线程,进行实时监听。
Thread client_listen = new Thread(listen_client);//启动线程开始监听
client_listen.IsBackground = true;
client_listen.Start();
第4、5步操作,监听到客户端,并将该客户端信息进行保存。
while(true)
{
Socket socket_watch = ServerSocket.Accept();//socket.accept保存了给Server发送信息的客户端的ip+port
this.Invoke(new Action(() =>
{
//向下拉框中添加一个客户端的ip端口字符串,作为客户的唯一标识
client_ips.Items.Add(socket_watch.RemoteEndPoint.ToString().Substring(0, socket_watch.RemoteEndPoint.ToString().IndexOf(":")));
}
));
//将与客户端通信的套接字对象socket_watch添加到键值对集合中,并以客户端IP端口作为键
dictSocket.Add(socket_watch.RemoteEndPoint.ToString().Substring(0, socket_watch.RemoteEndPoint.ToString().IndexOf(":")), socket_watch);
第6步操作,即ServerSocket接收到ClientSocket的信息,以及给ClientSocket发送信息
在确定了ClientSocket后,监听其对ServerSocket发送的消息,即开启一个线程,来实现服务器接收消息功能。
try
{
ParameterizedThreadStart pts = new ParameterizedThreadStart(recmessge);//开启一个带有参数传递的线程,传递的参数为.start(参数)
Thread trd = new Thread(pts);
trd.IsBackground = true;
trd.Start(socket_watch);
dictThread.Add(socket_watch.RemoteEndPoint.ToString(), trd);
this.Invoke((MethodInvoker)delegate
{
server_receive.AppendText("Client"+socket_watch.RemoteEndPoint.ToString() + "已经上线");
});
}
catch
{
MessageBox.Show("1234", "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
下面是recmessage代码,读取receive的信息。
Socket socketRec=socketClientpara as Socket;//as作为强制转换
while(true)
{
byte[] arr_recmessage = new byte[1024 * 1024];
int length = -1;
try
{
length = socketRec.Receive(arr_recmessage);//字节长度
}
catch(SocketException ex)
{
}
catch(Exception ex)
{
}
string str = Encoding.UTF8.GetString(arr_recmessage, 0, length);
this.Invoke(new Action(() =>
{
//向下拉框中添加一个客户端的ip端口字符串,作为客户的唯一标识
server_receive.AppendText(client_ips.Text + ":\r\n" + str);//显示IP与信息
}
));
Thread.Sleep(10);
}
同理给Client发送消息也是类似代码
byte[] strSendMsg = Encoding.UTF8.GetBytes(sendMsg);
string strClientKey = client_ips.Text;//通过Key匹配对应ip地址的客户端
dictSocket[strClientKey].Send(strSendMsg);
this.Invoke(new Action(() =>
{
server_receive.AppendText("服务器:" + "\r\n" + sendMsg + "\r\n");
}));
send_msg.Text = null;
客户端
相对服务端,客户端的操作比较简单:(1)创建一个ClientSocket(2)建立Client与Server的联系(3)接收服务端消息以及发送消息
创建一个ClientSocket的流程与创建一个ServerSocket流程类似,只需要对服务端建立连接即可。代码如下:
int port = 50000;
string ip = "192.168.0.5";//服务器IP
IPAddress serverip = IPAddress.Parse(ip);//将IP地址字符串转换为IPAddress实例
Client_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//使用指定的地址簇协议、套接字类型和通信协议
IPEndPoint endPoint = new IPEndPoint(serverip, port);//用指定的ip和端口号初始化IPendPint实例
Client_Socket.Connect(endPoint);
然后接收服务端的消息,通过建立一个线程,来不断地接收服务端的信息。
Thread servert_listen = new Thread(RecMsg);//启动线程开始监听
servert_listen.IsBackground = true;
servert_listen.Start();
接收的消息:
byte[] arrRecMsg = new byte[1024 * 1024];
int length = Client_Socket.Receive(arrRecMsg);
string str = Encoding.UTF8.GetString(arrRecMsg, 0, length);
this.Invoke(new Action(() =>
{
receive_info.AppendText("服务器:" + "\r\n" + str + "\r\n");
}));
同理发送消息只需要将Receive更改为send即可
byte[] strSenMsg = Encoding.UTF8.GetBytes(sendMsg);
Client_Socket.Send(strSenMsg);
this.Invoke(new Action(() =>
{
receive_info.AppendText("客户端:" + "\r\n" + sendMsg + "\r\n");
}));
send_msg.Text = null;
2.Socket的通讯方式
Socket的通讯方式有两种:同步与异步
同步的工作方式:
用TCP协议进行编程时,程序执行到发送、接收和监听语句的时候,在未完成工作前,不再继续往下执行,即处于堵塞状态,直到该语句执行结束后,才会继续执行下一句。
异步的工作方式:
程序执行到发送、接收和监听语句的时候,不论工作是否完成,继续执行下一句。
3.通讯方式
在与服务端建立连接后,我们就可以通过此连接来发送和接收数据。端口与端口之间以流(Stream)的形式传输数据,因为几乎任何对象都可以保存在流中,所以可以在客户端与服务端之间传输任何类型的数据。对客户端来说,往流中写入数据,即为想服务器传输数据,从流中读取数据,即为从服务端接收数据。对于服务端也一样。
参考博客:
https://www.cnblogs.com/jamesping/articles/2071932.html
https://www.cnblogs.com/wangfx91/p/3997668.html
https://blog.csdn.net/u011602967/article/details/50728443/
https://blog.csdn.net/buctyyzyn/article/details/78704303