NET平台下C#socket通信(下)

上篇文章主要是简单介绍一下通信的过程以及机制。但实际上这中间简单的TCP的通信在实际应用中是比较的,利用C# TCP多线程的应用案例。

这边一起来分析一下多线程的代码,大家也可以在文章附带的Demo进行尝试。

我们点击启动服务按钮,服务器:

// 创建负责监听的套接字,注意其中的参数;

socketWatch =newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

// 获得文本框中的IP对象;

IPAddress address=IPAddress.Parse(txtIp.Text.Trim());

// 创建包含ip和端口号的网络节点对象;

IPEndPointendPoint =newIPEndPoint(address,int.Parse(txtPort.Text.Trim()));

try

{

// 将负责监听的套接字绑定到唯一的ip和端口上;

socketWatch.Bind(endPoint);

}

catch(SocketExceptionse)

{

MessageBox.Show("异常:"+se.Message);

return;

}

首先我们创建负责监听的套接字, 在Bind绑定后,我们创建了负责监听的线程。代码如下:

// 设置监听队列的长度;

socketWatch.Listen(10);

// 创建负责监听的线程;

threadWatch =newThread(WatchConnecting);

threadWatch.IsBackground =true;

threadWatch.Start();

ShowMsg("服务器启动监听成功!");

btnBeginListen.Enabled =false;

其中 WatchConnecting方法是负责监听新客户端请求的。然后让我们看一下WatchConnecting的代码。

///

///监听客户端请求的方法;

///

voidWatchConnecting()

{

while(true)// 持续不断的监听客户端的连接请求;

{

//开始监听客户端连接请求,Accept方法会阻断当前的线程;

SocketsokConnection = socketWatch.Accept();// 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;

// 想列表控件中添加客户端的IP信息;

lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());

// 将与客户端连接的 套接字 对象添加到集合中;

dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);

ShowMsg("客户端连接成功!");

Threadthr =newThread(RecMsg);

thr.IsBackground =true;

thr.Start(sokConnection);

dictThread.Add(sokConnection.RemoteEndPoint.ToString(), thr);// 将新建的线程 添加 到线程的集合中去。

}

}

这个线程是一直存在的,主要的任务就是监听是否有Client与Server端进行连接,如果连接成功则会另开一个线程”RecMsg”。在该线程中则主要是得到字符数据的处理,包括接受数据以及发送数据。

voidRecMsg(objectsokConnectionparn)

{

SocketsokClient = sokConnectionparnasSocket;

while(true)

{

// 定义一个2M的缓存区;

byte[] arrMsgRec =new byte[1024 * 1024 * 2];

// 将接受到的数据存入到输入 arrMsgRec中;

intlength = -1;

try

{

length = sokClient.Receive(arrMsgRec);// 接收数据,并返回数据的长度;

}

catch(SocketExceptionse)

{

ShowMsg("异常:"+ se.Message);

// 从 通信套接字 集合中删除被中断连接的通信套接字;

dict.Remove(sokClient.RemoteEndPoint.ToString());

// 从通信线程集合中删除被中断连接的通信线程对象;

dictThread.Remove(sokClient.RemoteEndPoint.ToString());

// 从列表中移除被中断的连接IP

lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());

break;

}

catch(Exceptione)

{

ShowMsg("异常:"+ e.Message);

// 从 通信套接字 集合中删除被中断连接的通信套接字;

dict.Remove(sokClient.RemoteEndPoint.ToString());

// 从通信线程集合中删除被中断连接的通信线程对象;

dictThread.Remove(sokClient.RemoteEndPoint.ToString());

// 从列表中移除被中断的连接IP

lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());

break;

}

if(arrMsgRec[0] == 0)// 表示接收到的是数据;

{

stringstrMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec,1, length-1);// 将接受到的字节数据转化成字符串;

ShowMsg(strMsg);

}

if(arrMsgRec[0] == 1)// 表示接收到的是文件;

{

SaveFileDialogsfd =newSaveFileDialog();

if(sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)

{// 在上边的 sfd.ShowDialog() 的括号里边一定要加上 this 否则就不会弹出 另存为 的对话框,而弹出的是本类的其他窗口,,这个一定要注意!!!【解释:加了this的sfd.ShowDialog(this),“另存为”窗口的指针才能被SaveFileDialog的对象调用,若不加thisSaveFileDialog 的对象调用的是本类的其他窗口了,当然不弹出“另存为”窗口。】

stringfileSavePath = sfd.FileName;// 获得文件保存的路径;

// 创建文件流,然后根据路径创建文件;

using(FileStreamfs =newFileStream(fileSavePath,FileMode.Create))

{

fs.Write(arrMsgRec, 1, length - 1);

ShowMsg("文件保存成功:"+ fileSavePath);

其实这就是建立多线程TCP通信的主要过程,这里值得注意的就是其实监听线程监听的一直都是一个固定的端口,在应用层如果建立建立连接了,则连接不会使用监听的端口号,而会使用另一个空闲的端口号,这样才能保证一直连接监听一直使用一个固定端口号,从而使得连接也变得更加容易。Demo有数据交换的,也有类似于通信的,大家都可以参考。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20171221G02KAP00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券