winform项目——仿QQ即时通讯程序09:socket通信示例程序

编程项目2019/12/20 21:00:17阅读:794

上一篇文章结束了CIM项目的界面搭建过程,从本篇文章开始,正式进行核心技术的分析与实现。本篇文章将对程序通讯的原理进行分析,用具体的例子演示通讯过程。CIM项目的核心就是基于这种通讯。

学习过网络的同学应该知道,两台设备之间进行信息的传递需要经过复杂的信息处理过程,不管是OSI模型还是TCP/IP模型都需要经过很多复杂的步骤才能进行通讯,其实这种抽象出来的通讯模型已经足够简单了,但是里面的具体实现是特别复杂的。两台设备通过IP地址进行身份确认,那么如何区分设备上不同的应用程序呢,其实是通过端口号进行区分的。用于网络通讯的应用程序,必然要使用一个或多个网络端口进行通讯,这样,对于同一个设备的不同程序,将使用端口号进行区分。一个端口只能同时由一个程序使用,因此我们常见的端口冲突就是多个程序都要使用同一个网络端口造成的。端口号的范围是0~65535,其中,1023以下的端口号已经预先分配给常用的应用程序了,所以我们编程时通常选择1024以上的端口号进行绑定。

编程语言将复杂的通讯过程封装起来,留给了开发者一个Socket用于通讯,我们通常叫它“套接字”。它可以指定通信的ip和端口号,我们只需要在程序中调用即可,不用管它底层如何传递的消息。下面,这是一个winform版利用socket进行通讯的例子。

首先,我们打开VS2015,新建一个windows窗体项目,叫做服务端程序。然后在窗体上拖两个按钮和一个label,如下图:

设计

一个写启动服务,一个写发送消息。 双击启动服务按钮,进入按钮的点击事件。然后输入如下代码以便移动,代码的意思已经包含在注释里:

private void button1_Click(object sender, EventArgs e)
{
//1.创建一个用于监听客户端连接的socket
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.绑定ip地址和端口号
socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234));
//3.设置连接数量
socket.Listen(100);
label1.Text = "已启动服务端程序!";
//4.接收请求连接的客户端socket
//此方法会一直尝试连接客户端socket,没有连接下面的代码就不会执行,该方法返回一个socket
//client_socket就是用于和客户端通信的socket
client_socket = socket.Accept();
//4.开启新线程用于实时接收客户端发来的消息
Thread acceptThread = new Thread(Receive_client);
acceptThread.IsBackground = true;
acceptThread.Start();
}


private void Receive_client()
{
while (true)
{
byte[] buffer = new byte[1024];//容纳1024个字节的字节数组
int len = client_socket.Receive(buffer);
string text = Encoding.UTF8.GetString(buffer,0,len);
label1.Text = "收到了消息:"+text;
}
}

注意里面的socket变量,把它写成全局变量,因为其它方法还要用到它。还有socket的Accept方法,如果接收到客户端,这个方法会卡在这里不往下走,所以一会测试的时候要先点击启动服务,再点击客户端程序上的“连接服务器”。

接着在发送消息按钮的点击事件中:

private void button2_Click(object sender, EventArgs e)
{
client_socket.Send(Encoding.UTF8.GetBytes("你好呀!我是服务端程序"));
}


private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
}

注意Form的加载事件的代码,因为我们在新开的线程中操作了主线程的label1,这句话的意思是关闭非法线程操作,不然的话会报错。

这样,服务端的程序就完成,接着再打开一个VS2015的窗口,再新建一个windows窗体项目,名称为客户端程序。按照下图进行布局:

布局

然后是连接服务按钮的点击事件:

private void button1_Click(object sender, EventArgs e)
{
//1.new一个socket用于连接服务器
c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.根据ip和端口连接服务器
c.Connect("127.0.0.1", 1234);
label1.Text = "已连接上服务器!";
//3.开启新线程用于实时接收服务端发来的消息
Thread acceptThread = new Thread(Receive_server);
acceptThread.IsBackground = true;
acceptThread.Start();
}


private void Receive_server()
{
while (true)
{
byte[] buffer = new byte[1024];//容纳1024个字节的字节数组
//接收消息
//receive方法未接收到消息之前也是卡在这个方法不动的。
int len = c.Receive(buffer);
string text = Encoding.UTF8.GetString(buffer, 0, len);
label1.Text = "收到了消息:" + text;
}
}

接着是发送消息按钮的点击事件:

private void button2_Click(object sender, EventArgs e)
{
c.Send(Encoding.UTF8.GetBytes("你好呀,我是客户端!"));
}


private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
}

同样的,也要关闭线程间通信检测。

这样,我们的客户端程序也做好了。

测试通信

1.我们分别启动服务端、客户端程序如下图:

两个程序

2.先点击服务端程序的“启动服务”按钮,再点击客户端“连接服务器”按钮,此时,两者的label上各显示“已启动服务端程序!”和“已连接上服务器”。注意,因为accept方法的原因,点了“启动服务”按钮之后,该窗体将会卡住,直到点击“连接服务器”按钮才会正常。

连接服务器

3.分别点击服务端程序和客户端程序的“发送消息”按钮,此时,两者将分别接受到消息并显示在label上。

收到消息

至此,我们的示例程序就做完了,本篇文章也结束了。一起做的同学需要多理解socket中的各种方法,后面才能更轻松地将socket融入到CIM项目中。

本文系小博客网站原创,转载请注明文章链接地址