C#TCP实现多个客户端与服务端数据与文件的传输.docx
《C#TCP实现多个客户端与服务端数据与文件的传输.docx》由会员分享,可在线阅读,更多相关《C#TCP实现多个客户端与服务端数据与文件的传输.docx(26页珍藏版)》请在冰豆网上搜索。
C#TCP实现多个客户端与服务端数据与文件的传输
C#菜鸟做这个东东竟然花了快三天的时间了,真是菜,菜,菜〜
F面是我用C#写的一个简单的TCP通信,主要的功能有:
(1)多个客户端与服务器间的数据交流
(2)可以实现群发的功能
(3)客户端与服务端可以进行文件的传输
主要用到的知识:
TCP里的socket、、多线程Thread、、
昵称:
雪
F面的是界面:
口-孤天弱容户揣
连接服势端
发送消息
选择文件
岌送文件
畫成成成成成成成盏而s雷S-.而山S-.而山S-1而户户户户户户户屢客ii—
IF
FOKT:
172.1612.12
S068
在线列表
172.16.12.12:
58063
172.16.12.12:
58064
172.IB.12.12:
56065
1T2.16.12.12:
58066
1T2.IB.12.12:
58067
172.15.12.12:
56068
172.10.12.12:
58069
1T2.16.12.1256OT0
选择文件
下面分别是服务端和客户端的代码,如若借用,请标明出处服务端代码:
[csharp]viewplaincopyprint?
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Net.Sockets;
usingSystem.Net;//IP,IPAddress,IPEndPoint,端口等;usingSystem.Threading;
usingSystem.IO;
namespace_11111
{
publicpartialclassfrm_server:
Form{
publicfrmserver。
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls=false;
}
ThreadthreadWatch=null;//负责监听客户端连接请求的线程;
SocketsocketWatch=null;
Dictionarydict=newDictionary();
DictionarydictThread=newDictionary();
privatevoidbtnBeginListen_Click(objectsender,EventArgse)
{
//创建负责监听的套接字,注意其中的参数;
socketWatch=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//获得文本框中的IP对象;
IPAddressaddress=IPAddress.Parse(txtIp.Text.Trim());
//创建包含ip和端口号的网络节点对象;
IPEndPointendPoint=newIPEndPoint(address,int.Parse(txtPort.Text.Trim()));
try
{
//将负责监听的套接字绑定到唯一的ip和端口上;socketWatch.Bind(endPoint);
}
catch(SocketExceptionse)
{
MessageBox.Show("异常:
"+se.Message);
return;
}
//设置监听队列的长度;socketWatch.Listen(10);
//创建负责监听的线程;
threadWatch=newThread(WatchConnecting);
threadWatch.IsBackground=true;
threadWatch.Start();
ShowMsg("服务器启动监听成功!
");
//}
}
///
///监听客户端请求的方法;
///
voidWatchConnecting()
{
while(true)//持续不断的监听客户端的连接请求;
{
//开始监听客户端连接请求,Accept方法会阻断当前的线程;
SocketsokConnection=socketWatch.Accept();//一旦监听到一个客户端的请求,就返回一个与该客户端通信的套接字;
//想列表控件中添加客户端的IP信息;lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());
//将与客户端连接的套接字对象添加到集合中;dict.Add(sokConnection.RemoteEndPoint.ToString(),sokConnection);
ShowMsg("客户端连接成功!
");
Threadthr=newThread(RecMsg);thr.IsBackground=true;
thr.Start(sokConnection);
dictThread.Add(sokConnection.RemoteEndPoint.ToString(),thr);//将新建的线程添加到线程的集合中去。
}
}
voidRecMsg(objectsokConnectionparn)
{
SocketsokClient=sokConnectionparnasSocket;
while(true)
{
//定义一个2M的缓存区;
byte[]arrMsgRec=newbyte[1024*1024*2];
//将接受到的数据存入到输入arrMsgRec中;
intlength=-1;
try
{
length=sokClient.Receive(arrMsgRec);//接收数据,并返回数据的长度;
}
catch(SocketExceptionse)
{
ShowMsg("异常:
"+se.Message);
//从通信套接字集合中删除被中断连接的通信套接字;dict.Remove(sokClient.RemoteEndPoint.ToString());
//从通信线程集合中删除被中断连接的通信线程对象;dictThread.Remove(sokClient.RemoteEndPoint.ToString());
//从列表中移除被中断的连接IPlbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());break;
}
catch(Exceptione)
{
ShowMsg("异常:
"+e.Message);
//从通信套接字集合中删除被中断连接的通信套接字;dict.Remove(sokClient.RemoteEndPoint.ToString());
//从通信线程集合中删除被中断连接的通信线程对象;dictThread.Remove(sokClient.RemoteEndPoint.ToString());
//从列表中移除被中断的连接IPlbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());
break;
}
if(arrMsgRec[0]==0)//表示接收到的是数据;
{
stringstrMsg=System.Text.Encoding.UTF8.GetString(arrMsgRec,1,length-1);//将接受到的字
节数据转化成字符串;
ShowMsg(strMsg);
}
if(arrMsgRec[0]==1)//表示接收到的是文件;
{
SaveFileDialogsfd=newSaveFileDialog();
if(sfd.ShowDialog(this)==System.Windows.Forms.DialogResult.OK)
{//在上边的sfd.ShowDialog()的括号里边一定要加上this否则就不会弹出另存为的对话框,而弹出的是本类的其他窗口,,这个一定要注意!
!
!
【解释:
加了this的sfd.ShowDialog(this),“另存为”窗口的指针才能被SaveFileDialog的对象调用,若不加thisSaveFileDialog的对象调用的是本类的其他窗口了,当然不弹出“另存为”窗口。
】
stringfileSavePath=sfd.FileName;//获得文件保存的路径;
//创建文件流,然后根据路径创建文件;
using(FileStreamfs=newFileStream(fileSavePath,FileMode.Create))
{
fs.Write(arrMsgRec,1,length-1);
ShowMsg("文件保存成功:
"+fileSavePath);
}
}
}
}
}
voidShowMsg(stringstr)
{
txtMsg.AppendText(str+"\r\n");
}
//发送消息
privatevoidbtnSend_Click(objectsender,EventArgse)
{
stringstrMsg="服务器"+"\r\n"+"-->"+txtMsgSend.Text.Trim()+"\r\n";
byte[]arrMsg=System.Text.Encoding.UTF8.GetBytes(strMsg);//将要发送的字符串转换成Utf-8字节数组;
byte[]arrSendMsg=newbyte[arrMsg.Length+1];arrSendMsg[0]=0;//表示发送的是消息数据
Buffer.BlockCopy(arrMsg,0,arrSendMsg,1,arrMsg.Length);
stringstrKey="";
strKey=lbOnline.Text.Trim();
if(string.IsNullOrEmpty(strKey))//判断是不是选择了发送的对象;
{
MessageBox.Show("请选择你要发送的好友!
!
!
");
}
else
{
dict[strKey].Send(arrSendMsg);//解决了sokConnection是局部变量,不能再本函数中引用的问题;
ShowMsg(strMsg);txtMsgSend.Clear();
}
}
///
///群发消息
///
///
///消息
privatevoidbtnSendToAll_Click(objectsender,EventArgse)
{
stringstrMsg="服务器"+"\r\n"+"-->"+txtMsgSend.Text.Trim()+"\r\n";
byte[]arrMsg=System.Text.Encoding.UTF8.GetBytes(strMsg);//将要发送的字符串转换成Utf-8字节数组;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Net.Sockets;
usingSystem.Net;//IP,IPAddress,IPEndPoint,端口等;
usingSystem.Threading;
usingSystem.IO;
namespace_11111
{
publicpartialclassfrm_server:
Form
{
publicfrm_server()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls=false;
}
ThreadthreadWatch=null;//负责监听客户端连接请求的线程;
SocketsocketWatch=null;
Dictionarydict=newDictionary();
DictionarydictThread=newDictionary();
privatevoidbtnBeginListen_Click(objectsender,EventArgse)
{
//创建负责监听的套接字,注意其中的参数;
socketWatch=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//获得文本框中的IP对象;
IPAddressaddress=IPAddress.Parse(txtIp.Text.Trim());
//创建包含ip和端口号的网络节点对象;
IPEndPointendPoint=newIPEndPoint(address,int.Parse(txtPort.Text.Trim()));
try
{
//将负责监听的套接字绑定到唯一的ip和端口上;socketWatch.Bind(endPoint);
}
catch(SocketExceptionse)
{
MessageBox.Show("异常:
"+se.Message);
return;
}
//设置监听队列的长度;socketWatch.Listen(10);
//创建负责监听的线程;threadWatch=newThread(WatchConnecting);threadWatch.IsBackground=true;threadWatch.Start();
ShowMsg("服务器启动监听成功!
");
//}
///
///监听客户端请求的方法;
///
voidWatchConnecting()
{
while(true)//持续不断的监听客户端的连接请求;
{
//开始监听客户端连接请求,Accept方法会阻断当前的线程;
SocketsokConnection=socketWatch.Accept();//一旦监听到一个客户端的请求,就返回一个与该客户端通信的套接字;
//想列表控件中添加客户端的IP信息;lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());
//将与客户端连接的套接字对象添加到集合中;dict.Add(sokConnection.RemoteEndPoint.ToString(),sokConnection);ShowMsg("客户端连接成功!
");
Threadthr=newThread(RecMsg);
thr.IsBackground=true;thr.Start(sokConnection);
dictThread.Add(sokConnection.RemoteEndPoint.ToString(),thr);//将新建的线程添加到线程的集合中去。
}
}
voidRecMsg(objectsokConnectionparn)
{
SocketsokClient=sokConnectionparnasSocket;
while(true)
{
//定义一个2M的缓存区;byte[]arrMsgRec=newbyte[1024*1024*2];
//将接受到的数据存入到输入arrMsgRec中;intlength=-1;
try
{
length=sokClient.Receive(arrMsgRec);//接收数据,并返回数据的长度;
}
catch(SocketExceptionse)
{
ShowMsg("异常:
"+se.Message);
//从通信套接字集合中删除被中断连接的通信套接字;
dict.Remove(sokClient.RemoteEndPoint.ToString());
//从通信线程集合中删除被中断连接的通信线程对象;dictThread.Remove(sokClient.RemoteEndPoint.ToString());
//从列表中移除被中断的连接IPlbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());break;
}
catch(Exceptione)
{
ShowMsg("异常:
"+e.Message);
//从通信套接字集合中删除被中断连接的通信套接字;dict.Remove(sokClient.RemoteEndPoint.ToString());
//从通信线程集合中删除被中断连接的通信线程对象;dictThread.Remove(sokClient.RemoteEndPoint.ToString());
//从列表中移除被中断的连接IPlbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());break;
}
if(arrMsgRec[0]==0)//表示接收到的是数据;
{
stringstrMsg=System.Text.Encoding.UTF8.GetString(arrMsgRec,1,length-1);//将接受到的字节数据转化成字符串;
ShowMsg(strMsg);
}
if(arrMsgRec[0]==1)//表示接收到的是文件;
{
SaveFileDialogsfd=newSaveFileDialog();
if(sfd.ShowDialog(this)==System.Windows.Forms.DialogResult.OK)
{//在上边的sfd.ShowDialog()的括号里边一定要加上
this否则就不会弹出另存为的对话框,而弹出的是本类的其他窗口,,这个一定要注意!
!
!
【解释:
加了this的sfd.ShowDialog(this),“另存为”窗口的指针才能被SaveFileDialog的对象调用,若不加thisSaveFileDialog的对象调用的是本类的其他窗口了,当然不弹出“另存为”窗口。
】
stringfileSavePath=sfd.FileName;//获得文件保存的路径;
//创建文件流,然后根据路径创建文件;using(FileStreamfs=newFileStream(fileSavePath,
FileMode.Create))
fs.Write(arrMsgRec,1,length-1);
ShowMsg("文件保存成功:
"+fileSavePath);
}
}
}
}
voidShowMsg(stringstr)
{txtMsg.AppendText(str+"\r\n");
}
//发送消息
privatevoidbtnSend_Click(objectsender,EventArgse)
{
stringstrMsg="服务器"+"\r\n"+"-->"+txtMsgSend.Text.Trim()+"\r\n";
byte[]arrMsg=System.Text.Encoding.UTF8.GetBytes(strMsg);//将要发送的字符串转换成Utf-8字节数组;
byte[]arrSendMsg=newbyte[arrMsg.Length+1];arrSendMsg[0]=0;//表示发送的是消息数据Buffer.BlockCopy(arrMsg,0,arrSendMsg,1,arrMsg.Length);stringstrKey="";
strKey=lbOnline.Text.Trim();
if(string.IsNullOrEmpty(strKey))//判断是不是选择了发送的对象;
{MessageBox.Show("请选择你要发送的好友!
!
!
");
}else{dict[strKey].Send(arrSendMsg);//解决了sokConnection是局部变量,不能再本函数中引用的问题;
ShowMsg(strMsg);txtMsgSend.Clear();
}
}
///
///群发消息
///
///
///消息
privatevoidbtnSendToAll_Click(objectsender,EventArgse)
{
stringstrMsg="服务器"+"\r\n"+"-->"+txtMsgSend.Text.Trim()+"\r\n";
byte[]arrMsg=System.Text.En