导航

黑马程序员----聊天程序练习

Posted on 2011-12-04 11:33  asp.net 开发  阅读(191)  评论(0)    收藏  举报

聊天程序客户端代码:

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;
using System.IO;

namespace socketClient
{
public partial class socketClinet : Form
{
public socketClinet()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}

Thread threadClient = null;//客户端负责接收服务端发来的消息
Socket socketClient = null;//客户端套接字
private void btnConnection_Click(object sender, EventArgs e)
{
IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
IPEndPoint endpoin = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketClient.Connect(endpoin);
//创建线程监听服务端发来的消息
threadClient = new Thread(RecMsg);
threadClient.IsBackground = true;
threadClient.Start();
}

void RecMsg()
{
while (true)
{
//定义一个接收的缓存区(2M字节数组)
byte[] arrMsgRec = new byte[1024 * 1024 * 2];
//将接收到的数组存入arryMsgRec数组并返回接收到的数据长度
int length = socketClient.Receive(arrMsgRec);
//此时是将数组所有的元素都转换成字符串,而真正接收到的只有服务端发来的几个字符
string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec,0,length);
showMsg(strMsgRec);
}
}

//向服务器发送文本消息
private void btnSendMsg_Click(object sender, EventArgs e)
{
string strMsg = txtMsgSend.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);
socketClient.Send(arrMsgSend);
showMsg("我说:"+strMsg);
}


#region 选择要发送的文件--btnChooseFile_Click
//用户选择要发送的文件
private void btnChooseFile_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtFilePath.Text = ofd.FileName;
}
}
#endregion


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的数组(缓存区)
//将文件读到数组中并获得读取的真实数据长度length
int length = fs.Read(arrFile, 0, arrFile.Length);
byte[] arrFileSend=new byte[length+1];
arrFileSend[0] = 1;//代表发送的是文件数据
//for (int i = 0; i < length; i++)
//{
// arrFileSend[i + 1] = arrFile[i];
////arrFile.CopyTo(arrFileSend,length);
//}
//将arrFile数组里的元素 从第0个开始拷贝,拷贝到arrFileSend数组里,从第一个位置开始存储,一共拷贝length个数据
//发送包含了标识位的新数组到服务器
Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length);
socketClient.Send(arrFileSend);
}
}

#region 在窗体文本框中显示消息--void showMsg(string msg)
/// <summary>
/// 在窗体文本框中显示消息
/// </summary>
/// <param name="msg"></param>
void showMsg(string msg)
{
txtMsg.Text += msg + "\r\n";
}
#endregion
}
}

聊天程序服务端代码:

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.Sockets;
using System.Net;
using System.Threading;
using System.IO;

namespace socket
{
public partial class socketServer : Form
{
public socketServer()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}
Thread threadWatch = null;//负责见他那个客户端连接请求的线程
Socket socketWatch = null;//负责监听的套接字
private void btnBeginServer_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(WatchConnection);
threadWatch.IsBackground = true;
threadWatch.Start();
showMsg("服务器启动监听成功!");
}

Socket sokConnecion = null;//负责通信的套接字
void showMsg(string msg)
{
txtMsg.Text += msg+"\r\n";
}
//保存了服务器所有负责和客户端通信的套接字
Dictionary<string, Socket> dic = new Dictionary<string, Socket>();
//保存了服务器多有负责调用通信套接字.Recived方法的线程
Dictionary<string, Thread> dicThread = new Dictionary<string, Thread>();

/// <summary>
/// 监听客户端请求的方法
/// </summary>
void WatchConnection()
{
while (true)
{
//开始监听客户端连接请求,注意:Accept方法,会阻断当前线程
Socket sokConnecion = socketWatch.Accept();
//向列表控件中添加一个客户端ip端口字符串,作为客户端的唯一标示符
lbOnline.Items.Add(sokConnecion.RemoteEndPoint.ToString());
//将与客户端通信的套接字对象sokConnection添加到对象集合中,并以客户端IP端口作为键
dic.Add(sokConnecion.RemoteEndPoint.ToString(), sokConnecion);

//创建通信线程
Thread thr = new Thread(RecMsg);
thr.IsBackground = true;
thr.Start(sokConnecion);
dicThread.Add(sokConnecion.RemoteEndPoint.ToString(),thr);
showMsg("客户端连接成功"+sokConnecion.RemoteEndPoint.ToString());
}
}

/// <summary>
/// 服务端负责监听客户端发来的数据的方法
/// </summary>
void RecMsg(object socketClientPara)
{
Socket socketClient = socketClientPara as Socket;
while (true)
{
//定义一个接收的缓存区(2M字节数组)
byte[] arrMsgRec = new byte[1024 * 1024 * 2];
//将接收到的数组存入arryMsgRec数组并返回接收到的数据长度
int length = socketClient.Receive(arrMsgRec);
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() == System.Windows.Forms.DialogResult.OK)//用户选择文件路径后
{
string fileSavePath = sfd.FileName;//获得要保存的文件路径
//创建文件流,然后让文件流根据路径创建一个文件
using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
{
fs.Write(arrMsgRec, 1, length-1);
showMsg("文件保存成功:"+fileSavePath);
}
}
}
}
}

private void btnSend_Click(object sender, EventArgs e)
{
string strMsg = txtMsgSend.Text.Trim();
if (string.IsNullOrEmpty(lbOnline.Text))
{
MessageBox.Show("请选择发送地址!!!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
//将要发送的字符串转成utf8对应的字符串数组
byte[] ArrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
//获得列表中选中的key
string strClientKey = lbOnline.Text;
//通过key。找到字典集合中对应的与某个客户端的套接字的send方法,发送数据给对方
dic[strClientKey].Send(ArrMsg);
//sokConnecion.Send(ArrMsg);
showMsg("发送了数据:" + strMsg);
}
}

//服务群发消息
private void btnSendAll_Click(object sender, EventArgs e)
{
string strMsg = txtMsgSend.Text.Trim();
//将要发送的字符串转成utf8对应的字符串数组
byte[] ArrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
foreach (Socket s in dic.Values)
{
s.Send(ArrMsg);
}
showMsg("群发完毕!");
}
}
}