程序下载地址:
http://download.csdn.net/detail/u010312811/9683748
1.基本流程
服务器:
(1)用指定的端口号和服务器的IP建立一个EndPoint对象
(2)建立一个Socket对象
(3)用Socket对象的Bind()方法绑定EndPoint
(4)用Socket对象的Listen()方法开始监听
(5)接受客户端的连接,用Socket对象的Accept()方法创建新的Socket对象用于和请求的客户端进行通信
(6)通信结束后一定要关闭Socket
客户端:
(1)用指定的端口号和服务器的IP建立一个EndPoint对象
(2)建立一个Socket对象
(3)用Socket对象的Connect()方法以上面建立的EndPoint对象作为参数,向服务器发出连接请求
(4)如果连接成功,就用Socket对象的Send()方法向服务器发送信息
(5)用Socket对象的Receive()方法接收服务器发来的信息
(6)通信结束后需要关闭Socket
2.功能及效果图:
- Server和Client进行封装,方便调用
- 消息进行封装,消息收发利用Linq
- 消息使用事件进行发布订阅,降低耦合度
- 支持消息发送、文件发送(文件大小不超过10M)
- 服务器端支持用户昵称,上下线提醒
3.服务器功能介绍:
(1)服务器开始监听:
- 订阅消息接收事件
- 订阅文件接收事件
- 订阅用户的登陆、退出事件
1 //服务器开始监听端口
2 server.StartListen(txtIp.Text, int.Parse(txtPort.Text));
3 //服务器接收到消息
4 server.MessageReceived += server_MessageReceived;
5 //服务器接收到文件
6 server.FileReceived += server_FileReceived;
7 //服务器订阅用户的登录退出事件
8 server.UserLogIn += server_UserLogIn;
9 server.UserLogOut += server_UserLogOut;
10
11 txtMsgReceive.Text += "服务器开始监听!
";
(2)消息的发送:
- 获取需要发送的消息
- 将消息进行封装
- 获取需要接收数据的客户端IP
- 发送消息
1 //获取需要发送的消息
2 string strMsg = txtMsgSend.Text;
3 //填充数据结构
4 MessageBase mb = new MessageBase();
5 mb.UserName = "服务器";
6 mb.MessageType = MessageType.Message; //消息类型
7 mb.Messages = Encoding.Default.GetBytes(strMsg); //发送的消息转换为字节数组
8 mb.FileName = ""; //发送消息,文件名填空
9 //获取用户名和用户IP
10 string name=lbOnlineList.SelectedItem.ToString();
11 string ip=server.GetUserID(name);
12 //发送消息
13 if (name != "")
14 server.SendMessage(ip, mb);
15 else
16 MessageBox.Show("错误!");
(3)文件的发送:
- 获取本地文件路径
- 通过FileStream读取文件,并将文件保存为byte数组
- 将消息进行封装
- 获取需要接收数据的客户端IP
- 发送消息
1 //获取文件路径
2 string filePath = txtSelectFile.Text;
3 //发送消息
4 using (FileStream fs = new FileStream(filePath, FileMode.Open))
5 {
6 byte[] arrFile = new byte[bufferSize];
7 int length = fs.Read(arrFile, 0, arrFile.Length);
8 byte[] arrFileSend = new byte[length];
9 Array.Copy(arrFile, 0, arrFileSend, 0, length);
10
11 MessageBase mb = new MessageBase();
12 mb.UserName = "服务器";
13 mb.MessageType = MessageType.File; //消息类型
14 mb.Messages = arrFileSend; //文件转换为字节数组
15 mb.FileName = Path.GetFileName(filePath); //文件名
16 //获取用户名和用户IP
17 string name = lbOnlineList.SelectedItem.ToString();
18 string ip = server.GetUserID(name);
19 //发送文件
20 if (name != "")
21 server.SendFile(ip, mb);
22 else
23 MessageBox.Show("错误!");
24 }
(4)消息的接收:
- 获取消息的封装
- 获取消息并处理数据
1 string strMsg = Encoding.Default.GetString(mb.Messages);
2 Action Update = () =>
3 {
4 txtMsgReceive.Text += string.Format("{0}[{1}]:
{2}
",mb.UserName,DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"),strMsg );
5 };
6 //Invoke(Update); //同步的方法
7 BeginInvoke(Update); //异步的方法
(5)文件的接收:
- 另存为对话框提示,获取保存的路径及文件名
- 提取消息并进行处理
1 Action Update = () =>
2 {
3 //弹出保存对话框
4 SaveFileDialog sfd = new SaveFileDialog();
5 sfd.FileName = mb.FileName;
6 DialogResult dr = sfd.ShowDialog();
7
8 if (dr == DialogResult.OK)
9 {
10 //获取文件保存的路径
11 string fileSavePath = sfd.FileName;
12 //创建文件流,然后根据路径创建文件
13 using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
14 {
15 fs.Write(mb.Messages, 0, mb.Messages.Length);
16 MessageBox.Show("文件保存成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand);
17 }
18 }
19 };
20 Invoke(Update);
(6)有新用户登录:
- 获取系统中的用户列表
- 更新用户显示列表
1 string[] users = server.GetUsers();
2 Action Update = () =>
3 {
4 lbOnlineList.Items.Clear();
5 for (int i = 0; i < users.Length; i++)
6 {
7 lbOnlineList.Items.Add(users[i]);
8 }
9
10 lbOnlineList.SelectedIndex = 0;
11 };
12 Invoke(Update);
(7)用户退出:
- 获取系统中的用户列表
- 更新用户显示列表
1 string[] users = server.GetUsers(); 2 Action Update = () => 3 { 4 lbOnlineList.Items.Clear(); 5 for (int i = 0; i < users.Length; i++) 6 { 7 lbOnlineList.Items.Add(users[i]); 8 } 9 }; 10 Invoke(Update);
4.客户端功能介绍:
(1)连接服务器:
- 实例化一个客户端
- 客户端连接到服务器
- 订阅客户端的消息接收事件、文件接收事件
1 client = new Client();
2 client.ConnectServer(txtIp.Text, int.Parse(txtPort.Text));
3 //客户端接收到消息
4 client.MessageReceived += client_MessageReceived;
5 //客户端接收到文件
6 client.FileReceived += client_FileReceived;
(2)消息的发送:
- 获取需要发送的消息
- 对消息进行封装
- 向服务器发送消息
1 //获取需要发送的消息
2 string strMsg = txtSendMsg.Text;
3 //填充数据结构
4 MessageBase mb = new MessageBase();
5 mb.UserName = txtName.Text; //用户名
6 mb.MessageType = MessageType.Message; //消息类型
7 mb.Messages = Encoding.Default.GetBytes(strMsg); //发送的消息转换为字节数组
8 mb.FileName = ""; //发送消息,文件名填空
9 //客户端向服务器发送消息
10 client.SendMessage(mb);
(3)文件的发送:
- 获取本地文件路径
- 通过FileStream读取文件,并将文件保存为byte数组
- 将消息进行封装
- 获取需要接收数据的客户端IP
- 发送文件
1 //获取文件路径
2 string filePath = txtSelectFile.Text;
3 //发送消息
4 using (FileStream fs = new FileStream(filePath, FileMode.Open))
5 {
6 byte[] arrFile = new byte[bufferSize];
7 int length = fs.Read(arrFile, 0, arrFile.Length);
8 byte[] arrFileSend = new byte[length];
9 Array.Copy(arrFile, 0, arrFileSend, 0, length);
10
11 MessageBase mb = new MessageBase();
12 mb.UserName = txtName.Text; //用户名
13 mb.MessageType = MessageType.File; //消息类型
14 mb.Messages = arrFileSend; //文件转换为字节数组
15 mb.FileName = Path.GetFileName(filePath); //文件名
16
17 client.SendFile(mb);
18 }
(4)消息的接收:
- 获取消息的封装
- 获取消息并处理数据
1 string strMsg = Encoding.Default.GetString(mb.Messages);
2 Action Update = () =>
3 {
4 txtReceiveMsg.Text += string.Format("{0}[{1}]:
{2}
", mb.UserName, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), strMsg);
5 };
6 //Invoke(Update); //同步
7 BeginInvoke(Update); //异步
(5)文件的接收:
- 另存为对话框提示,获取保存的路径及文件名
- 提取消息并进行处理
1 Action Update = () =>
2 {
3 //弹出保存对话框
4 SaveFileDialog sfd = new SaveFileDialog();
5 sfd.FileName = mb.FileName; ;
6 DialogResult dr = sfd.ShowDialog();
7
8 if (dr == DialogResult.OK)
9 {
10 string fileSavePath = sfd.FileName;//获取文件保存的路径
11 //创建文件流,然后根据路径创建文件
12 using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
13 {
14 fs.Write(mb.Messages, 0, mb.Messages.Length);
15 MessageBox.Show("文件保存成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand);
16 }
17 }
18 };
19 Invoke(Update);