黑马程序员 Socket网络编程--聊天室
2013-07-01 12:56
573 查看
------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------
一、 网络中进程之间如何通信?
首先解决的问题是:如何唯一标识一个进程,否则通信无从谈起。在本地,可以用进程的PID来唯一标识一个进程,而在网路中则行不通。TCP/IP协议族已解决了这个问题:网络层的“IP地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(Ip地址,协议,端口)就可以标识网络中的进程了,网络中的进程标识就可以利用这个标识与其他进程进行交互。
二、 什么是Socket
用于描述IP地址和端口,是一个通信链的句柄。通过Socket可以接收和发送网络上的数据。
三、 Socket一般应用模式(服务端和客户端)
1、 服务端的Socket(至少需要两个)
(1) 一个负责接收客户端连接请求(但不负责通信);
(2) 每成功接收到一个客户端的连接便在服务端产生一个对应的Socket。
2、 客户端的Socket
(1) 必须指定要连接的服务端ip和端口;
(2) 通过创建一个Socket对象来初始化一个到服务端的TCP连接。
四、 Socket的通讯过程
1、 服务端
a) 申请一个socket
b) 绑定到Ip地址和端口
c) 开启监听
d) 等待客户端的连接请求。
2、 客户端
a) 申请一个socket
b) 向服务器发起连接(指明Ip地址和端口号)。
五、 面向连接的套接字调用时序
六、 实例:聊天程序
功能:服务端和客户端互相收发消息,服务端可以接受多个客户端的连接请求,并与之通信。
1、服务端程序:
服务端代码分析:
a) Socket.Accept()成员方法,会阻断当前线程,所以需要创建一个新线程执行该操作。
b) 每当有一个客户端连接服务器时,就创建一个Socket负责和客户端通信。这里用Dictionary<string,Socket>泛型,存储两者的对应关系。服务端向客户端发消息时,从Dictionary字典中取出与客户端对应的服务端Socket,然后用该Socket发送消息;
c) Receive方法会阻断当前线程,因此服务端在监听到客户端的连接请求后,就创建一个新线程来执行新连接的通信,接收客户端的消息;
d) CheckForIllegalCrossThreadCalls=false:关闭跨线程访问控件的检查,这里threadWath线程访问了UI线程创建的TextBox控件txtRecMsg,默认是不允许的,所以这里设置该属性为false,就可以跨线程访问了。
2、 客户端代码
客户端代码分析:
a) 首先申请一个Socket,指定服务端的ip和端口,请求连接(Connect);
b) 客户端需要不断的接收服务端的消息,所以创建一个后台线程,不断的循环接收(Receive)消息,如果收到消息,显示出来;
c) 如果服务器关闭了连接,客户端报SocketException异常。捕获该异常,提示“服务器已断开连接”,然后不再继续接收服务端的消息。
六、 实例:异常处理
Server和Client建立连接后,先关闭Client窗口,服务器代码报异常:
“未处理:SocketException 远程主机强迫关闭了一个现有的连接。”
解决办法:try-catch捕获SocketException,然后关闭当前服务端Socket,并中断接收客户端消息。
服务端接收消息的部分代码如下:
一、 网络中进程之间如何通信?
首先解决的问题是:如何唯一标识一个进程,否则通信无从谈起。在本地,可以用进程的PID来唯一标识一个进程,而在网路中则行不通。TCP/IP协议族已解决了这个问题:网络层的“IP地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(Ip地址,协议,端口)就可以标识网络中的进程了,网络中的进程标识就可以利用这个标识与其他进程进行交互。
二、 什么是Socket
用于描述IP地址和端口,是一个通信链的句柄。通过Socket可以接收和发送网络上的数据。
三、 Socket一般应用模式(服务端和客户端)
1、 服务端的Socket(至少需要两个)
(1) 一个负责接收客户端连接请求(但不负责通信);
(2) 每成功接收到一个客户端的连接便在服务端产生一个对应的Socket。
2、 客户端的Socket
(1) 必须指定要连接的服务端ip和端口;
(2) 通过创建一个Socket对象来初始化一个到服务端的TCP连接。
四、 Socket的通讯过程
1、 服务端
a) 申请一个socket
b) 绑定到Ip地址和端口
c) 开启监听
d) 等待客户端的连接请求。
2、 客户端
a) 申请一个socket
b) 向服务器发起连接(指明Ip地址和端口号)。
五、 面向连接的套接字调用时序
六、 实例:聊天程序
功能:服务端和客户端互相收发消息,服务端可以接受多个客户端的连接请求,并与之通信。
1、服务端程序:
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; //引入命名空间 using System.Net; //IPAddress、IPEndPoint类 using System.Net.Sockets; using System.Threading; namespace Server_END { public partial class Server_End : Form { public Server_End() { InitializeComponent(); //关闭对跨线程非安全代码调用的检查 Server_End.CheckForIllegalCrossThreadCalls =false; } //在文本框显示信息 void ShowMsg(string msg) { txtRecMsg.AppendText(msg + "\n"); } //负责监听的Socket Socket sockWatch = null; //key:远程主机的ip、端口,value:负责和该主机通信的服务端Socket Dictionary<string, Socket> dict = new Dictionary<string, Socket>(); //开启监听服务 private void btnStartService_Click(object sender, EventArgs e) { //获得文本框中的ip地址的对象 IPAddress ipAddr = IPAddress.Parse(txtIP.Text.Trim()); //创建包含ip和端口的网络节点对象 IPEndPoint localEP = new IPEndPoint(ipAddr, Convert.ToInt32(txtPort.Text.Trim())); //创建 服务端 负责监听的Socket对象(使用ipv4,使用流式连接,使用TCP协议传输数据) sockWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //绑定IP和端口 sockWatch.Bind(localEP); //开始监听 sockWatch.Listen(10); ShowMsg("服务器已启动监听..."); //创建新线程,处理客户端的连接请求 Thread threadWath = new Thread(WatchAccp); threadWath.IsBackground = true; threadWath.Start(); } /// <summary> /// 监听连接请求 /// </summary> void WatchAccp() { while (true) { //接受连接请求并创建新Socket Socket sockCon = sockWatch.Accept(); //显示远程主机的ip和端口 lbOnline.Items.Add(sockCon.RemoteEndPoint.ToString()); //添加字典 dict.Add(sockCon.RemoteEndPoint.ToString(), sockCon); ShowMsg("和客户端已建立连接:" + sockCon.RemoteEndPoint.ToString()); //为新Socket创建线程,负责和客户端通信 object obj = sockCon; Thread threadCon = new Thread(RecMsg); threadCon.IsBackground = true; threadCon.Start(obj); } } /// <summary> /// 接收消息 /// </summary> void RecMsg(object obj) { Socket sockCon = (Socket)obj; //创建消息缓冲区 byte[] msgBuffer = new byte[1024 * 1024 * 2]; while (true) { //将接收的消息存放到缓冲区,并返回字节数 int count = sockCon.Receive(msgBuffer); //将字节数据转换为string string strRecMsg = Encoding.UTF8.GetString(msgBuffer); ShowMsg(string.Format("接收自{0}:{1}", sockCon.RemoteEndPoint.ToString(), strRecMsg)); } } //发送消息 private void btnSend_Click(object sender, EventArgs e) { if (lbOnline.Text.Trim().Length > 0) { string clientEP = lbOnline.Text; //从字典中查到和某客户端通信的Socket Socket sockCon = dict[clientEP]; //将string转换为byte数据 byte[] msgBuffer = Encoding.UTF8.GetBytes(txtSndMsg.Text.Trim()); //发送消息 sockCon.Send(msgBuffer); } } } }
服务端代码分析:
a) Socket.Accept()成员方法,会阻断当前线程,所以需要创建一个新线程执行该操作。
b) 每当有一个客户端连接服务器时,就创建一个Socket负责和客户端通信。这里用Dictionary<string,Socket>泛型,存储两者的对应关系。服务端向客户端发消息时,从Dictionary字典中取出与客户端对应的服务端Socket,然后用该Socket发送消息;
c) Receive方法会阻断当前线程,因此服务端在监听到客户端的连接请求后,就创建一个新线程来执行新连接的通信,接收客户端的消息;
d) CheckForIllegalCrossThreadCalls=false:关闭跨线程访问控件的检查,这里threadWath线程访问了UI线程创建的TextBox控件txtRecMsg,默认是不允许的,所以这里设置该属性为false,就可以跨线程访问了。
2、 客户端代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Threading; namespace Client_END { public partial class Client_End : Form { public Client_End() { InitializeComponent(); Client_End.CheckForIllegalCrossThreadCalls = false; } //在文本框显示信息 void ShowMsg(string msg) { txtRecMsg.AppendText(msg + "\r\n"); } Socket sockClient = null; private void btnConnect_Click(object sender, EventArgs e) { IPAddress ipAddr = IPAddress.Parse(txtIP.Text.Trim()); IPEndPoint remoteEP = new IPEndPoint(ipAddr, Convert.ToInt32(txtPort.Text.Trim())); sockClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // sockClient.Connect(remoteEP); } private void btnSend_Click(object sender, EventArgs e) { byte[] strSndMsg = Encoding.UTF8.GetBytes(txtSndMsg.Text.Trim()); sockClient.Send(strSndMsg); ShowMsg("发送了:" + txtSndMsg.Text.Trim()); } } }
客户端代码分析:
a) 首先申请一个Socket,指定服务端的ip和端口,请求连接(Connect);
b) 客户端需要不断的接收服务端的消息,所以创建一个后台线程,不断的循环接收(Receive)消息,如果收到消息,显示出来;
c) 如果服务器关闭了连接,客户端报SocketException异常。捕获该异常,提示“服务器已断开连接”,然后不再继续接收服务端的消息。
六、 实例:异常处理
Server和Client建立连接后,先关闭Client窗口,服务器代码报异常:
“未处理:SocketException 远程主机强迫关闭了一个现有的连接。”
解决办法:try-catch捕获SocketException,然后关闭当前服务端Socket,并中断接收客户端消息。
服务端接收消息的部分代码如下:
void RecMsg(object obj) { Socket sockCon = (Socket)obj; //创建消息缓冲区 byte[] msgBuffer = new byte[1024 * 1024 * 2]; while (true) { try { //将接收的消息存放到缓冲区,并返回字节数 int count = sockCon.Receive(msgBuffer); //将字节数据转换为string string strRecMsg = Encoding.UTF8.GetString(msgBuffer, 0, count); ShowMsg("接收自" + sockCon.RemoteEndPoint.ToString() + ":" + strRecMsg); } catch (SocketException e) { //客户端断开了连接,关闭与之通信的服务端Socket sockCon.Close(); //不再接收已关闭的客户端消息 break; } } }------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------
相关文章推荐
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务4[聊天室]
- [网络编程]——TCP_Socket通信_聊天室_客户端多线程.初步形成
- Java网络编程,通过TCP,Socket实现多对一的局域网聊天室
- 黑马程序员-java网络编程基础——socket编程基础
- java网络编程——Socket和ServerSocket,套接字编程——简单聊天室
- java网络编程,通过TCP,Socket实现多对一的局域网聊天室
- 网络编程_TCP_Socket通信原理_多个客户端_聊天室原理JAVA189-190
- [网络编程]——网络编程_TCP_Socket通信_聊天室.雏形
- java网络编程,通过TCP,Socket实现多对一的局域网聊天室 .
- java网络编程,通过TCP,Socket实现多对一的局域网聊天室
- java网络编程,通过TCP,Socket实现多对一的局域网聊天室
- [黑马程序员九]:Socket网络编程
- 黑马程序员---网络编程(socket编程)
- android网络编程 -- Socket 通信(03) 点对点Android聊天室实现(带服务器) [附源码分析]
- 黑马程序员——java基础——Socket网络编程
- 【黑马程序员】黑马入学准备篇:网络编程之 TCP、UDP和Socket综合实例
- Linux socket网络编程之聊天室(三):select异步通讯实现
- Linux socket网络编程之聊天室(三):select异步通讯实现
- 黑马程序员----------Java网络编程(Socket编程)笔记
- 基于Socket编程的网络聊天室