数往知来 asp.net 聊天室问题解决方案<十六>
1:在服务端创建了一个负责监听的sokcet
//三个:采用TCP协议.
ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse(this.txtIP.Text);//获取IP地址.
IPEndPoint point = new IPEndPoint(ipAddress, Convert.ToInt32(this.txtPort.Text));
//通信节点.包含了IP地址与端口号.
ListenSocket.Bind(point);//将通信节点(IP地址与端口号)与负责监听的Socket进行绑定。
ListenSocket.Listen(10);//设置监听队列.(将当前的Socket设置侦听状态)
2:解决服务端Accept方法占用UI线程的问题.(必做)
ThreadStart start = new ThreadStart(AcceptConnection);
Thread thread = new Thread(start);
thread.IsBackground = true;
//设置后台线程.如果整个的服务端窗体关闭,也就没有必要再等带客户端了,
所以在这里把该线程设置为后台线程。
thread.Start();
3:解决多个客户端请求,针对不同的客户端创建单独的newSocket(可选)
public void AcceptConnection()
{
while (true)//由于每个客户端必须都有一个单独的newSocket实例与之进行交流,
所以我们服务端得Accept()方法一致等待客户端有没有链接过来。
{
Socket newSocket = ListenSocket.Accept();
//获取到一个客户端的请求,创建一个新的Socket,负责与客户端进行交流
。每个客户都要创建一个单独的newSocket.
ShowMsg("客户端链接成功");
}
}
4:客户端怎样连接了服务端.
在客户端中添加如下代码:
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse(this.txtIP.Text);//获取IP地址.
IPEndPoint endPoint = new IPEndPoint(ipAddress,Convert.ToInt32(this.txtPort.Text));
//clientSocket.Bind(endPoint);
clientSocket.Connect(endPoint);//客户端根据通信节点去链接服务端。在客户端不能进行Bind操作.
5:服务端怎样向客户端发送文本数据.
首先在服务添加如下代码
/// <summary>
/// 服务端向客户端发送文本数据(发送按钮)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSendMsg_Click(object sender, EventArgs e)
{
string sendMsg = this.txtSendMsg.Text;
byte[] buffer=System.Text.Encoding.UTF8.GetBytes(sendMsg);//send发送的是字节数组.
newSocket.Send(buffer);//服务端向客户端发送数据.
ShowMsg("发送成功!");
}
以上代码中我们将newSocket定义了一个全局变量,这样会有问题。
客户端的代码(放在了客户端的 private void btnStartListen_Click(object sender, EventArgs e)方法中)
byte[] buffer=new byte[1024*1024*2];
clientSocket.Receive(buffer);
//接收服务端发过来的数据,该法会让客户端的Socket一直处于一种接收状态。
所以该方法也会占用UI线程。
string receiveMsg=System.Text.Encoding.UTF8.GetString(buffer);
ShowMsg(receiveMsg);
6:解决客户端接收数据的Receive方法占用UI线程问题,以及newSocket全局问题
客户端解决Receive占用UI线程问题。
ThreadStart start = new ThreadStart(ReciveClient);
//解决客户端接收Receive方法占用UI线程的问题。
Thread thread = new Thread(start);
thread.IsBackground = true;
thread.Start();
public void ReciveClient()
{
* * ];
clientSocket.Receive(buffer);
//接收服务端发过来的数据,该法会让客户端的Socket一直处于一种接收状态。
所以该方法也会占用UI线程。
string receiveMsg = System.Text.Encoding.UTF8.GetString(buffer);
ShowMsg(receiveMsg);
}
7:解决newSocket全局问题
//将与客户端进行数据交流的newSocket放入该集合中。
Dictionary<string, Socket> dictSocket = new Dictionary<string, Socket>();
public void AcceptConnection()
{
while (true)//由于每个客户端必须都有一个单独的newSocket实例与之进行交流,
所以我们服务端得Accept()方法一致等待客户端有没有链接过来。
{
Socket newSocket = ListenSocket.Accept();//获取到一个客户端的请求,
创建一个新的Socket,负责与客户端进行交流。每个客户都要创建一个单独的newSocket.
//将每个与客户端进行交流的newSocket添加到集合中,
我们用远程的客户端的IP地址与端口号作为集合的key.
dictSocket.Add(newSocket.RemoteEndPoint.ToString(), newSocket);
//将客户端的IP地址与端口号放在了列表中
this.listOnline.Items.Add(newSocket.RemoteEndPoint.ToString());
ShowMsg("客户端链接成功");
}
}
/// <summary>
/// 服务端向客户端发送文本数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSendMsg_Click(object sender, EventArgs e)
{
string sendMsg = this.txtSendMsg.Text;
byte[] buffer=System.Text.Encoding.UTF8.GetBytes(sendMsg);//send发送的是字节数组.
string clientIp = this.listOnline.Text;
if (!string.IsNullOrEmpty(clientIp))
{
//newSocket.Send(buffer);//服务端向客户端发送数据.
//根据用户在listBox列表中选择的客户端的iP地址与端口号,找到该客户端对应的newSocket.
dictSocket[clientIp].Send(buffer);
ShowMsg("发送成功!");
}
else
{
MessageBox.Show("请选择要发送的客户端");
}
}
8:客户端一直处于接收状态.
while (true)//也要让客户端一直处于接收状态.(只是增加了改循环)
{
* * ];
clientSocket.Receive(buffer);
//接收服务端发过来的数据,该法会让客户端的Socket一直处于一种接收状态。
所以该方法也会占用UI线程。
string receiveMsg = System.Text.Encoding.UTF8.GetString(buffer);
ShowMsg(receiveMsg);
}
9:解决回车换行问题.
public void ReciveClient()
{
while (true)//也要让客户端一直处于接收状态.
{
* * ];
int receiveLength=clientSocket.Receive(buffer);
//接收服务端发过来的数据,该法会让客户端的Socket一直处于一种接收状态
。所以该方法也会占用UI线程。
//如果接收的服务端发过来的数据不足2M,那么剩余的存储单元都用"\0"来填充,
而"\0"表示字符串的结束,所以我们在接受的字符串后面加回车换行时无效。
// string receiveMsg = System.Text.Encoding.UTF8.GetString(buffer);
//sokecet中的Receive方法会将接收到的数据填充到字节数组中,同时返回一个整数,
表示实际接收的数据长度。那么我们在将字节数组转成字符串时,从字节数组中的第一位开始,
一直实际接收的数据长度接收。这时不包含\0,
, receiveLength);
ShowMsg(receiveMsg);
}
}
数往知来 asp.net 聊天室问题解决方案<十六>的更多相关文章
- 学习ASP.NET Core Razor 编程系列十六——排序
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- ASP.NET Core 2.2 : 二十六. 应用JWT进行用户认证
本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案(ASP.NET Core 系列目录) 一.什么是JWT? JWT(json web token ...
- ASP.NET Core 2.2 : 二十六. 应用JWT进行用户认证及Token的刷新
来源:https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_26.html 本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及T ...
- Asp.Net Web API 2第十六课——Parameter Binding in ASP.NET Web API(参数绑定)
导航 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html. 本文主要来讲解以下内容: ...
- 学习ASP.NET Core Razor 编程系列十八——并发解决方案
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- SilverLight搭建WCF聊天室详细过程[转]
http://www.silverlightchina.net/html/zhuantixilie/getstart/2011/0424/7148.html 默认节点 SilverLight搭建WCF ...
- 学习ASP.NET Core Razor 编程系列十九——分页
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- Java进阶:基于TCP通信的网络实时聊天室
目录 开门见山 一.数据结构Map 二.保证线程安全 三.群聊核心方法 四.聊天室具体设计 0.用户登录服务器 1.查看当前上线用户 2.群聊 3.私信 4.退出当前聊天状态 5.离线 6.查看帮助 ...
- ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十四)之漏掉的客服消息
前言 不知不觉已经十四篇了,其实已经没有什么可写了.但是突然发现layim中带的客服功能没有用到.于是乎,抽点时间完成吧.其实之前的工作已经把客服功能完成了一大半,剩下的我们稍微调整即可.今天的演示我 ...
随机推荐
- mysql命令分类(DML、DDL、DCL)
DML:数据操作语言(操作数据) SELECT - 从数据库表中获取数据 UPDATE - 更新数据库表中的数据 DELETE - 从数据库表中删除数据 INSERT INTO - 向数据库表中插入数 ...
- Elsevier 投稿各种状态总结
Elsevier 投稿各种状态总结1. Submitted to Journal 当上传结束后,显示的状态是Submitted to Journal,这个状态是自然形成的无需处理.2. Wi ...
- SPOJ 1811 Longest Common Substring 后缀自动机
模板来源:http://www.neroysq.com/?p=76 思路:http://blog.sina.com.cn/s/blog_7812e98601012dfv.html 题意就是求两个字符串 ...
- Android InputMethodManager输入法简介
正文 一.结构 public final class InputMethodManager extends Object Java.lang.Object android.view.inputmeth ...
- [原]poj-2488-water-DFS
题目大意: 输入一个p*q的棋盘, 行用数字表示, 列用大写字母表示 , 1 <= p*q <= 26, 输出能够把棋盘全部空格走完且每个空格只走一次的字典序最小的路径.不存在则输出“im ...
- html5 移动端单页面布局
序 移动端的web网页使用的是响应式设计,但一般我们看到的网站页面都是跳转刷新得到的,比如通过点击一个menu后进入到另一个页面 今天来说下是移动端的单页面的布局.单页面就是一切操作和布局都是 ...
- Head first javascript
基础 <script type="text/javascript"> function validateNumber(value) { // Validate the ...
- Mobile Assistant
闲来无事,分享一个小东西--手机小助手,历时两周,这里选择几个不错的界面以示效果! 如果有感兴趣的部分,欢迎随时交流!
- HDU 1072 (不一样的入队条件) Nightmare
之前的BFS都是需要一个标记数组,但这个题不一样,因为可能一个格子不止走一次. 那么我们就要寻找新的入队条件:left比上次经过的时候大才入队(left表示上次经过该点时剩余的时间). 为什么呢?我们 ...
- Strlen()与sizeof()
在学习C语言时以及面试中,经常会见到strlen()与sizeof()这一对容易混淆的概念,搞清楚这两个概念,往往考察了编程人员对语言的基本掌握能力. 首先大家先明确两个概念是: 1.strlen() ...