黑马程序员-简单聊天室
来源:互联网 发布:办公室网络被限制 编辑:程序博客网 时间:2024/05/19 19:14
---------------------- Windows Phone 7手机开发、Net培训、期待与您交流! ----------------------
socket的英文原义是“孔”或“插座”。作为进程通信机制,取后一种意思。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄.(其实就是两个程序通信用的)
http使用80端口 ftp使用21端口 smtp使用23端口
socket有两种类型:
流式socket(stream)
是一种面向连接的socket,针对于面向连接的TCP服务应用,安全,但是效率低。
数据报式socket(datagram)
是一种无连接的socket,对应于无连接的UDP服务应用,不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高。
Socket一般应用模式(服务器端和客服端)
1.服务端welcoming socket 开始监听端口(负责监听客服端连接信息)
2.客服端client socket连接服务端指定端口(负责接收和发送服务端消息)
3.服务端welcoming socket监听到客户端连接,创建connection socket(负责和客服端通信)
Socketde的通讯过程
服务器端:
申请一个socket
绑定到一个IP地址和一个端口上
开启侦听,等待接受连接
客户端:
申请一个socket
连接服务器(指明IP地址和端口号)
服务器端接到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并 进行通讯,原侦听socket继续侦听。
简单聊天室
服务端
public partial class FChatServer : Form { public FChatServer() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false; } Thread threadWatch=null; Socket socketWatch = null; private void button1_Click(object sender, EventArgs e) { //创建 服务端负责监听的套接字,参数(使用IP4地址协议,使用流式连接,使用TCP协议传输数据); socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //获取 文本框IP地址对象 IPAddress address = IPAddress.Parse(txtIP.Text.Trim()); //创建 包含ip和port的网络节点对象 IPEndPoint endpoint = new IPEndPoint(address,int.Parse(txtPort.Text.Trim())); //将负责监听的套接字绑定到唯一的IP和端口上 socketWatch.Bind(endpoint); //设置监听队列长度 socketWatch.Listen(10); //创建负责监听的线程,传入监听方法 threadWatch = new Thread(WatchConnecting); threadWatch.IsBackground = true; threadWatch.Start(); ShowMsg("服务器启动监听成功!"); } //保存了服务器端所有负责和客服端通信的套接字 Dictionary<string, Socket> dict = new Dictionary<string, Socket>(); //保存了服务器端所有负责调用通信套接字Recive方法的线程 Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>(); /// <summary> /// 监听 客服端请求的方法 /// </summary> /// <param name="msg"></param> void WatchConnecting() { //持续不断的监听新客服端的连接请求 while (true) { //开始监听客服端连接请求,accept方法,会阻断当前的线程 Socket sokConnection = socketWatch.Accept();//一旦监听到客服端的请求 ,就返回一个负责和该客服端通信的套接字sokConnection //向列表控件中添加一个客服端的IP端口字符串,作为 客服端的唯一标识 lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString()); //将与客服端通信的套接字对象sokConnection添加到键值对集合中,并以客服端IP端口作为键 dict.Add(sokConnection.RemoteEndPoint.ToString(),sokConnection); //创建通信线程 Thread thr = new Thread(RecMsg); thr.IsBackground = true; thr.Start(sokConnection); dictThread.Add(sokConnection.RemoteEndPoint.ToString(),thr); ShowMsg("客服端连接成功!"); } } /// <summary> /// 服务端负责监听客服端发送来的数据的方法 /// </summary> void RecMsg(object socketClientPara) { Socket socketClient = socketClientPara as Socket; while (true) { //定义一个接收用的缓存区(2M字节数组) byte[] arrMsgRec = new byte[1024 * 1024 * 2]; //将接收到的数据存入arrMsgRec数组,返回真正就收到的数据长度 int length = -1; try { length = socketClient.Receive(arrMsgRec); } catch (SocketException ex) { ShowMsg("异常:" + ex.Message); //从通信套接字集合中删除被中断连接的通信套接字对象 dict.Remove(socketClient.RemoteEndPoint.ToString()); //从通信线程集合中删除被终端连接的通信线程对象 dictThread.Remove(socketClient.RemoteEndPoint.ToString()); //从列表中移除被中断的ip:port lbOnline.Items.Remove(socketClient.RemoteEndPoint.ToString()); break; } catch (Exception ex) { ShowMsg("异常:" + ex.Message); break; } if (arrMsgRec[0] == 0)//判断发送过来的数据的第一个元素是0,则代表发送来的是文字数据 { //此时是将数组的所有元素都转成字符串,而真正接收到的只有服务器发来的几个字符 string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length-1); ShowMsg(strMsgRec); } else if (arrMsgRec[0] == 1)//如果是1,代表发送来的是文件数据(图片/视频/文件...) { SaveFileDialog sfd = new SaveFileDialog(); if (sfd.ShowDialog() == DialogResult.OK) { string fileSavePath = sfd.FileName;//获得要保存的文件路径 using (FileStream fs = new FileStream(fileSavePath, FileMode.Create)) { fs.Write(arrMsgRec,1,length-1); ShowMsg("文件保存成功"); } } } } } void ShowMsg(string msg) { txtMessage.AppendText(msg+"\r\n"); } //发送消息到客服端 private void btnSend_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(lbOnline.Text)) { MessageBox.Show("请选择要发送的好友"); return; } string strMsg = txtMsgSend.Text.Trim(); //将要发送的字符串转成utf-8对应的字节数组 byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); //获得列表中选中的KEY string strClientKey = lbOnline.Text; //通过KEY,找到字典集合中对应的与某个 客服端通信的套接字的send方法,发送数据给对方 try { dict[strClientKey].Send(arrMsg); ShowMsg("发送了数据:" + strMsg); } catch (SocketException ex) { ShowMsg("发送时异常:" + ex.Message); return; } catch (Exception ex) { ShowMsg("发送时异常:" + ex.Message); return; } } private void btnSendAll_Click(object sender, EventArgs e) { string strMsg = txtMsgSend.Text.Trim(); byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); try { foreach (Socket s in dict.Values) { s.Send(arrMsg); } ShowMsg("群发完毕!"); } catch (SocketException ex) { ShowMsg("发送时异常:" + ex.Message); return; } catch (Exception ex) { ShowMsg("发送时异常:" + ex.Message); return; } } }
客服端
public partial class Form1 : Form { public Form1() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false; } Thread threadClient = null;//客服端负责接收服务端发来数据消息的线程 Socket socketClient=null; private void btnConnect_Click(object sender, EventArgs e) { IPAddress address = IPAddress.Parse(txtIP.Text.Trim()); IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim())); socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketClient.Connect(endpoint); threadClient = new Thread(RecMsg); threadClient.IsBackground = true; threadClient.Start(); } void RecMsg() { while (true) { //定义一个接收用的缓存区(2M字节数组) byte[] arrMsgRec = new byte[1024 * 1024 * 2]; //将接收到的数据存入arrMsgRec数组,返回真正就收到的数据长度 int length=socketClient.Receive(arrMsgRec); //此时是将数组的所有元素都转成字符串,而真正接收到的只有服务器发来的几个字符 string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec,0,length); ShowMsg(strMsgRec); } } void ShowMsg(string msg) { txtMessage.AppendText(msg + "\r\n"); } //向服务器发送文本消息 private void btnSend_Click(object sender, EventArgs e) { string strMsg = txtSendMsg.Text.Trim(); //将字符串转成方便网络传送的二进制数据 byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); byte[] arrMsgSend=new byte[arrMsg.Length+1]; arrMsgSend[0] = 0;//设置标识位 Buffer.BlockCopy(arrMsg, 0, arrMsgSend, 1, arrMsg.Length); try { socketClient.Send(arrMsgSend); ShowMsg("我说:"+strMsg); } catch (SocketException ex) { ShowMsg("发送时异常:" + ex.Message); return; } catch (Exception ex) { ShowMsg("发送时异常:" + ex.Message); return; } } //选择要发送的文件 private void btnChooseFile_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.OK) { txtFilePath.Text = ofd.FileName; } } //发送文件 private void btnSendFile_Click(object sender, EventArgs e) { //用文件流打开用户选择的文件 using (FileStream fs = new FileStream(txtFilePath.Text, FileMode.Open)) { byte[] arrFile = new byte[1024 * 1024 * 2];//定义一个2M的数组(缓存区) //将文件数据读到数组arrFile中,并获得读取的真实数据长度Length int length=fs.Read(arrFile,0,arrFile.Length); byte[] arrFileSend=new byte[length+1]; arrFileSend[0] = 1;//代表发送的是文件数据 //将arrFile数组里的元素从第0个开始拷贝,拷贝到arrFileSend数组里,从第1个开始存放,一共拷贝length个数据 Buffer.BlockCopy(arrFile,0,arrFileSend,1,length); try { //发送包含了标识位的新数据数组到服务端 socketClient.Send(arrFileSend); } catch (SocketException ex) { ShowMsg("发送时异常:" + ex.Message); return; } catch (Exception ex) { ShowMsg("发送时异常:" + ex.Message); return; } } } }
上面的代码没实现客服端之间的消息传送
---------------------- Windows Phone 7手机开发、Net培训、期待与您交流! ----------------------
详细请查看: http://net.itheima.com
- 黑马程序员-简单聊天室
- 黑马程序员-多线程聊天室
- 黑马程序员--多线程与套接字组合:简单聊天室(1)
- 黑马程序员--多线程与套接字组合:简单聊天室(2)
- 黑马程序员-006聊天室程序
- 黑马程序员之聊天室设计
- 《黑马程序员》Udp之聊天室
- 黑马程序员_聊天室学习(一)
- 黑马程序员 Socket网络编程--聊天室
- 黑马程序员----网络编程UDP多线程聊天室
- 黑马程序员_多线程socket聊天室
- 黑马程序员——Socket网络编程聊天室
- 黑马程序员—多线程聊天室(Socket介绍+源码)
- 黑马程序员C#网络编程之聊天室程序
- 简单聊天室
- 简单聊天室
- 简单聊天室
- 【黑马程序员】简单流操作
- flex设置Alert框的位置
- android-使用ViewGroup实现左右滑动切换界面的效果
- http抓包工具推荐WSockExpert/httpwatch/HttpAnalyzer/DebugBar
- Brew MP 中 IQI 指针的说明
- hdu 1069 Monkey and banana
- 黑马程序员-简单聊天室
- git服务器端及客户端安装--April
- 还是通畅工程(HDU1233)
- 借助U-boot进行一些内存地址的再次研究(二维数组及指针数组)
- Java中String 转换 int
- FT5406_touch
- PHP调用mysql_connect()函数报错:Call to undefined function mysql_connect()解决办法
- 因緣錯失難再復
- Rq图结构水题~