局域网qq,无客户端和服务端之分,局域网的计算机运行本程序就可以互相看见,可以自由聊天和传文件。
本版较之1.0版的改进之处:
使用数据结构类型传送数据;
增加传文件功能(有进度条);
考虑大家重现本程序方便,本程序一直没有用到任何额外的控件和子窗体
版本依然是在vs2003下编译,只要贴进编译器中就可以重现。
在vs2005下编译只需要在“窗体设计器生成的代码”里面加一句:
system.windows.forms.control.checkforillegalcrossthreadcalls = false;
using system;
using system.drawing;
using system.collections;
using system.componentmodel;
using system.windows.forms;
using system.data;
using system.net;
using system.net.sockets;
using system.text;
using system.threading;
using system.io;
namespace myqq
{
/// <summary>
/// form1 的摘要说明。
/// </summary>
public class form1 : system.windows.forms.form
{
public bool runing=false; //标志
public udpclient listen=new udpclient(2525);
public ipendpoint end;
public ipaddress groupaddress=ipaddress.parse("255.255.255.255"); //广播地址
public int groupport=2525; //广播端口
public ipaddress myip;
public string myname;
public string romename;
public ipaddress romeip;
public string romecon;
public senddata mysenddata = new senddata(); //本地的0号命令发送包
public bool isfile;//传送文件标志
public string savepath;//传文件的保存地址
public string romefilename;//远程文件名
public string romefilel;//远程文件用单位表示的长度,格式为 43m或437k
public filestream sendfilestream;//发送文件流
private system.windows.forms.listbox box;
private system.windows.forms.label label1;
private system.windows.forms.label label2;
private system.windows.forms.button button1;
private system.windows.forms.button button3;
private system.windows.forms.textbox t_rec;
private system.windows.forms.textbox t_send;
private system.windows.forms.button button2;
private system.windows.forms.button newmsg;
private system.windows.forms.label online;
private system.windows.forms.tooltip tooltip1;
private system.windows.forms.imagelist imagelist1;
private system.windows.forms.linklabel linklabel1;
private system.windows.forms.label label3;
private system.windows.forms.button button4;
private system.windows.forms.openfiledialog openfiledialog1;
private system.windows.forms.textbox t_filep;
private system.windows.forms.savefiledialog savefiledialog1;
private system.windows.forms.panel processa;
private system.windows.forms.progressbar progressbar1;
private system.windows.forms.panel processb;
private system.windows.forms.progressbar progressbar2;
private system.componentmodel.icontainer components;
public form1()
{
//
// windows 窗体设计器支持所必需的
//
initializecomponent();
//
// todo: 在 initializecomponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.dispose();
}
}
base.dispose( disposing );
}
#region windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void initializecomponent()
{
this.components = new system.componentmodel.container();
system.resources.resourcemanager resources = new system.resources.resourcemanager(typeof(form1));
this.box = new system.windows.forms.listbox();
this.t_rec = new system.windows.forms.textbox();
this.label1 = new system.windows.forms.label();
this.label2 = new system.windows.forms.label();
this.t_send = new system.windows.forms.textbox();
this.button1 = new system.windows.forms.button();
this.button3 = new system.windows.forms.button();
this.online = new system.windows.forms.label();
this.button2 = new system.windows.forms.button();
this.newmsg = new system.windows.forms.button();
this.tooltip1 = new system.windows.forms.tooltip(this.components);
this.imagelist1 = new system.windows.forms.imagelist(this.components);
this.linklabel1 = new system.windows.forms.linklabel();
this.label3 = new system.windows.forms.label();
this.t_filep = new system.windows.forms.textbox();
this.button4 = new system.windows.forms.button();
this.openfiledialog1 = new system.windows.forms.openfiledialog();
this.savefiledialog1 = new system.windows.forms.savefiledialog();
this.processa = new system.windows.forms.panel();
this.progressbar1 = new system.windows.forms.progressbar();
this.processb = new system.windows.forms.panel();
this.progressbar2 = new system.windows.forms.progressbar();
this.processa.suspendlayout();
this.processb.suspendlayout();
this.suspendlayout();
//
// box
//
this.box.itemheight = 12;
this.box.location = new system.drawing.point(0, 32);
this.box.name = "box";
this.box.size = new system.drawing.size(200, 352);
this.box.tabindex = 0;
//
// t_rec
//
this.t_rec.backcolor = system.drawing.systemcolors.inactiveborder;
this.t_rec.forecolor = system.drawing.color.fromargb(((system.byte)(192)), ((system.byte)(64)), ((system.byte)(0)));
this.t_rec.location = new system.drawing.point(208, 56);
this.t_rec.multiline = true;
this.t_rec.name = "t_rec";
this.t_rec.scrollbars = system.windows.forms.scrollbars.vertical;
this.t_rec.size = new system.drawing.size(328, 136);
this.t_rec.tabindex = 1;
this.t_rec.text = "";
//
// label1
//
this.label1.location = new system.drawing.point(208, 40);
this.label1.name = "label1";
this.label1.size = new system.drawing.size(120, 16);
this.label1.tabindex = 2;
this.label1.text = "接收:";
//
// label2
//
this.label2.location = new system.drawing.point(208, 200);
this.label2.name = "label2";
this.label2.size = new system.drawing.size(48, 16);
this.label2.tabindex = 2;
this.label2.text = "发送:";
//
// t_send
//
this.t_send.location = new system.drawing.point(208, 224);
this.t_send.multiline = true;
this.t_send.name = "t_send";
this.t_send.scrollbars = system.windows.forms.scrollbars.vertical;
this.t_send.size = new system.drawing.size(328, 120);
this.t_send.tabindex = 1;
this.t_send.text = "";
//
// button1
//
this.button1.location = new system.drawing.point(440, 352);
this.button1.name = "button1";
this.button1.size = new system.drawing.size(75, 32);
this.button1.tabindex = 3;
this.button1.text = "发 送";
this.button1.click += new system.eventhandler(this.button1_click);
//
// button3
//
this.button3.flatstyle = system.windows.forms.flatstyle.popup;
this.button3.location = new system.drawing.point(120, 5);
this.button3.name = "button3";
this.button3.size = new system.drawing.size(56, 23);
this.button3.tabindex = 4;
this.button3.text = "刷 新";
this.button3.click += new system.eventhandler(this.button3_click);
//
// online
//
this.online.font = new system.drawing.font("宋体", 9f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((system.byte)(134)));
this.online.forecolor = system.drawing.color.blue;
this.online.location = new system.drawing.point(8, 8);
this.online.name = "online";
this.online.size = new system.drawing.size(88, 16);
this.online.tabindex = 5;
this.online.text = "在线用户:";
//
// button2
//
this.button2.location = new system.drawing.point(352, 352);
this.button2.name = "button2";
this.button2.size = new system.drawing.size(75, 32);
this.button2.tabindex = 6;
this.button2.text = "清 空";
this.button2.click += new system.eventhandler(this.button2_click);
//
// newmsg
//
this.newmsg.location = new system.drawing.point(208, 56);
this.newmsg.name = "newmsg";
this.newmsg.size = new system.drawing.size(328, 136);
this.newmsg.tabindex = 7;
this.newmsg.text = "有新消息了!";
this.newmsg.click += new system.eventhandler(this.newmsg_click);
//
// imagelist1
//
this.imagelist1.imagesize = new system.drawing.size(32, 32);
this.imagelist1.imagestream = ((system.windows.forms.imageliststreamer)(resources.getobject("imagelist1.imagestream")));
this.imagelist1.transparentcolor = system.drawing.color.transparent;
//
// linklabel1
//
this.linklabel1.location = new system.drawing.point(264, 200);
this.linklabel1.name = "linklabel1";
this.linklabel1.size = new system.drawing.size(48, 16);
this.linklabel1.tabindex = 8;
this.linklabel1.tabstop = true;
this.linklabel1.text = "传文件";
this.linklabel1.linkclicked += new system.windows.forms.linklabellinkclickedeventhandler(this.linklabel1_linkclicked);
//
// label3
//
this.label3.location = new system.drawing.point(208, 240);
this.label3.name = "label3";
this.label3.size = new system.drawing.size(72, 16);
this.label3.tabindex = 9;
this.label3.text = "文件地址:";
//
// t_filep
//
this.t_filep.borderstyle = system.windows.forms.borderstyle.fixedsingle;
this.t_filep.location = new system.drawing.point(272, 232);
this.t_filep.name = "t_filep";
this.t_filep.size = new system.drawing.size(233, 21);
this.t_filep.tabindex = 10;
this.t_filep.text = "";
//
// button4
//
this.button4.flatstyle = system.windows.forms.flatstyle.popup;
this.button4.location = new system.drawing.point(504, 232);
this.button4.name = "button4";
this.button4.size = new system.drawing.size(32, 21);
this.button4.tabindex = 11;
this.button4.text = "…";
this.button4.click += new system.eventhandler(this.button4_click);
//
// processa
//
this.processa.backcolor = system.drawing.systemcolors.window;
this.processa.controls.add(this.progressbar1);
this.processa.location = new system.drawing.point(224, 264);
this.processa.name = "processa";
this.processa.size = new system.drawing.size(288, 24);
this.processa.tabindex = 12;
//
// progressbar1
//
this.progressbar1.location = new system.drawing.point(8, 6);
this.progressbar1.name = "progressbar1";
this.progressbar1.size = new system.drawing.size(272, 12);
this.progressbar1.step = 5;
this.progressbar1.tabindex = 0;
//
// processb
//
this.processb.backcolor = system.drawing.systemcolors.control;
this.processb.controls.add(this.progressbar2);
this.processb.location = new system.drawing.point(224, 112);
this.processb.name = "processb";
this.processb.size = new system.drawing.size(288, 24);
this.processb.tabindex = 12;
//
// progressbar2
//
this.progressbar2.location = new system.drawing.point(8, 6);
this.progressbar2.name = "progressbar2";
this.progressbar2.size = new system.drawing.size(272, 12);
this.progressbar2.step = 5;
this.progressbar2.tabindex = 0;
//
// form1
//
this.autoscalebasesize = new system.drawing.size(6, 14);
this.clientsize = new system.drawing.size(544, 389);
this.controls.add(this.processb);
this.controls.add(this.processa);
this.controls.add(this.t_send);
this.controls.add(this.button4);
this.controls.add(this.t_filep);
this.controls.add(this.label3);
this.controls.add(this.linklabel1);
this.controls.add(this.button2);
this.controls.add(this.online);
this.controls.add(this.button3);
this.controls.add(this.button1);
this.controls.add(this.label1);
this.controls.add(this.box);
this.controls.add(this.label2);
this.controls.add(this.t_rec);
this.controls.add(this.newmsg);
this.icon = ((system.drawing.icon)(resources.getobject("$this.icon")));
this.name = "form1";
this.text = "小y";
this.closing += new system.componentmodel.canceleventhandler(this.form1_closing);
this.load += new system.eventhandler(this.form1_load);
this.processa.resumelayout(false);
this.processb.resumelayout(false);
this.resumelayout(false);
}
#endregion
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[stathread]
static void main()
{
application.run(new form1());
}
//数据包格式
public struct senddata
{
public byte commandno;//命令号 1字节
public ipaddress fromip;//发送端ip 4字节
public int namelength; //名字的字节数 4字节
public string computername;//计算机名 x字节
public ipaddress toip;//接收端ip; 4字节
public string content;//内容 y字节
}
private void form1_load(object sender, system.eventargs e)
{
end=new ipendpoint(groupaddress,groupport);
//初始化计算机名和端口
iphostentry myentry=dns.gethostbyname(dns.gethostname());
myip = new ipaddress(myentry.addresslist[0].address);
myname = dns.gethostname();
box.items.add("ip 主机名");
//开启监听线程
runing=true;
thread mythread=new thread(new threadstart(this.listenport));
mythread.isbackground = false;
mythread.start();
//发送上线信息
mysenddata.commandno = 0;
mysenddata.fromip = myip;
mysenddata.computername = myname;
mysenddata.toip = myip;
mysenddata.content = "上线提示";
byte[] sendb = structtobytes(mysenddata);
sendpack(sendb);
//初始化窗体位置
t_send.height=120;
t_send.top=224;
linklabel1.text="传文件";
processa.visible=false;//发送的进度
processb.visible=false;//接收的进度
}
//侦听指定端口的广播地址udp包
public void listenport()
{
ipendpoint tempend=new ipendpoint(ipaddress.any,2525);
while(runing)
{
application.doevents();
try
{
byte[] recb=listen.receive(ref tempend);
// 检查所接收到的信息and处理之
checkmessage(recb);
}
catch(exception e)
{
messagebox.show("出现错误:"+e.message.tostring());
break;
}
}
listen.close();
box.items.add("线程已经退出!");
runing=false;
}
//循环接收包
public void checkmessage(byte[] recbb)
{
senddata recdata=bytestostruct(recbb);
romename=recdata.computername;
romeip=recdata.fromip;
romecon=recdata.content;
switch(recdata.commandno)
{
case 0x00: //刷新
if (recdata.toip.equals(myip))
{
if(box.findstring(recdata.fromip.tostring()+" "+recdata.computername)<=0)
box.items.add(recdata.fromip.tostring() + " " + recdata.computername);
online.text="在线用户:"+(box.items.count-1)+"人";
}
else if(recdata.fromip.equals(recdata.toip))
{
//从其他机器发送过来的刷新请求
//返回自己的信息
mysenddata.commandno = 0x00;
mysenddata.toip = recdata.toip;
mysenddata.content = "上线提示";
byte[] sendb = structtobytes(mysenddata);
sendpack(sendb);
//如果不存在则添加该用户
if (box.findstring(recdata.fromip.tostring() + " " + recdata.computername) <= 0)
box.items.add(recdata.fromip.tostring() + " " + recdata.computername);
}
break;
case 0x01: //发言
if (recdata.toip.equals(myip)&&!isfile)
{//当传送的不包含文件时才显示“有新消息了”
showne();
}
break;
case 0x02: //请求传文件
if(recdata.toip.equals(myip))
{//准备接收文件
romefilename=romecon.split('+')[0];
romefilel=romecon.split('+')[1];
readyrecfile();
}
break;
case 0x03://传文件
if(recdata.toip.equals(myip))
{//传送文件
thread mysend=new thread(new threadstart(sendfile));
mysend.start();
}
break;
case 0x09: //确认包
if (recdata.toip.equals(myip))
messagebox.show("信息来自:"+recdata.computername+"("+recdata.fromip.tostring()+")/r/n"+recdata.content,"消息");
break;
}
}
//发送数据包到广播地址
public void sendpack(byte[] sendbs)
{
try
{
listen.send(sendbs, sendbs.length, end);
}
catch(exception e)
{
messagebox.show(e.message.tostring());
}
}
//struct转换成byte[]
public static byte[] structtobytes(senddata structobj)
{
byte[] commandb=new byte[1];
commandb[0]=structobj.commandno;
byte[] fromipb=structobj.fromip.getaddressbytes();
byte[] nameb=encoding.default.getbytes(structobj.computername);
byte[] lengthb=bitconverter.getbytes(nameb.length);
byte[] toipb=structobj.toip.getaddressbytes();
byte[] contentb=encoding.default.getbytes(structobj.content);
byte[] buffer=new byte[13+nameb.length+contentb.length];
int index=0;
commandb.copyto(buffer,index);
index+=commandb.length;
fromipb.copyto(buffer,index);
index+=fromipb.length;
lengthb.copyto(buffer,index);
index+=lengthb.length;
nameb.copyto(buffer,index);
index+=nameb.length;
toipb.copyto(buffer,index);
index+=toipb.length;
contentb.copyto(buffer,index);
return buffer;
}
//byte转换成struct
public static senddata bytestostruct(byte[] bytes)
{
senddata myre=new senddata();
myre.commandno=bytes[0];
byte[] ipb=new byte[4];
array.copy(bytes,1,ipb,0,4);
myre.fromip=ipaddress.parse(ipbytetostring(ipb));
myre.namelength=bitconverter.toint32(bytes,5);
myre.computername=encoding.default.getstring(bytes,9,myre.namelength);
array.copy(bytes,9+myre.namelength,ipb,0,4);
myre.toip=ipaddress.parse(ipbytetostring(ipb));
myre.content=encoding.default.getstring(bytes,13+myre.namelength,bytes.length-13-myre.namelength);
return myre;
}
//将byte[]表示的ip地址转换成ipaddress类型
public static string ipbytetostring(byte[] ipbt)
{
string temp="";
temp=(int)ipbt[0]+"."+(int)ipbt[1]+"."+(int)ipbt[2]+"."+(int)ipbt[3];
return temp;
}
//刷新
private void button3_click(object sender, system.eventargs e)
{
box.items.clear();
box.items.add("ip 主机名");
mysenddata.commandno = 0;
mysenddata.fromip = myip;
mysenddata.computername = myname;
mysenddata.toip = myip;
mysenddata.content = "上线提示";
byte[] sendb = structtobytes(mysenddata);
sendpack(sendb);
}
//关闭循环
private void form1_closing(object sender, system.componentmodel.canceleventargs e)
{
runing=false;
udpclient mm=new udpclient();
ipendpoint tempipend=new ipendpoint(ipaddress.parse("127.0.0.1"),2525);
mysenddata.commandno = 0;
mysenddata.fromip = myip;
mysenddata.computername = myname;
mysenddata.toip = myip;
mysenddata.content = "上线提示";
byte[] sendb = structtobytes(mysenddata);
mm.send(sendb,sendb.length,tempipend);
}
//发送
private void button1_click(object sender, system.eventargs e)
{
if(box.selecteditem==null||box.selectedindex==0)
{
messagebox.show("请先选择一个用户!");
return;
}
if(linklabel1.text=="不传文件"&&t_filep.text!="")
{//需要传文件
//首先发送2号命令 要求对方准备接收
sendfilestream=new filestream(t_filep.text,filemode.open,fileaccess.read);
long filelength=sendfilestream.length;
string totalsteps;
int temp;
if(filelength/(1024*1024)>10)
{//文件>10m时用m做为进度最小单位
temp=(int)(filelength/(1024*1024));
totalsteps=temp+"m";
}
else
{//小于10m的文件用k做为最小单位
temp=(int)(filelength/1024);
totalsteps=temp+"k";
}
//用做接收端时的公共变量保存发送的临时值
romefilel=totalsteps;
string filename=path.getfilename(t_filep.text);
mysenddata.commandno = 0x02;
mysenddata.fromip = myip;
mysenddata.computername = myname;
mysenddata.toip = ipaddress.parse(box.selecteditem.tostring().split(' ')[0]);
mysenddata.content = filename+"+"+totalsteps;//格式:yy.txt+62k+64990
byte[] sendb = structtobytes(mysenddata);
sendpack(sendb);
//界面上的处理
t_send.height=120;
t_send.top=224;
linklabel1.text="传文件";
}
//发言
if(t_send.text=="")
{
return;
}
mysenddata.commandno = 0x01;
mysenddata.fromip = myip;
mysenddata.computername = myname;
mysenddata.toip = ipaddress.parse(box.selecteditem.tostring().split(' ')[0]);
mysenddata.content = t_send.text;
byte[] sendb2 = structtobytes(mysenddata);
sendpack(sendb2);
}
//清空
private void button2_click(object sender, system.eventargs e)
{
t_send.text=string.empty;
t_rec.text=string.empty;
}
//单击显示接收的信息并隐藏自身
private void newmsg_click(object sender, system.eventargs e)
{
if(isfile)
{//当传送的含有文件时
savefiledialog1.filter="所有格式|*.*";
savefiledialog1.filename=romefilename;
if(savefiledialog1.showdialog()==dialogresult.ok)
savepath=savefiledialog1.filename;
else
return;
t_rec.text="消息来自"+romename+"("+romeip.tostring()+")"+datetime.now.toshortdatestring();
t_rec.text+="/r/n> "+romecon;
//界面的处理
newmsg.sendtoback();
t_send.height=120;
t_send.top=224;
linklabel1.text="传文件";
//返回一个确认接收包
mysenddata.commandno = 0x03;
mysenddata.fromip = myip;
mysenddata.computername = myname;
mysenddata.toip = romeip;
mysenddata.content = "ready!";
byte[] sendb = structtobytes(mysenddata);
sendpack(sendb);
//复位文件标志
isfile=false;
//同时开启线程开始监听
thread myrecv=new thread(new threadstart(listenport));
myrecv.start();
return;
}
t_rec.text="消息来自"+romename+"("+romeip.tostring()+")"+datetime.now.toshortdatestring();
t_rec.text+="/r/n> "+romecon;
mysenddata.commandno = 0x09;
mysenddata.toip = romeip;
mysenddata.content = "信息被打开!";
byte[] sendb2 = structtobytes(mysenddata);
sendpack(sendb2);
newmsg.sendtoback();
}
//当有信息时显示提示按钮
public void showne()
{
//窗体显示
if(this.windowstate!=formwindowstate.normal)
{
this.visible=true;
this.windowstate=formwindowstate.normal;
}
newmsg.text="有新消息了";
newmsg.bringtofront();
}
//准备接收文件
public void readyrecfile()
{
//窗体显示
if(this.windowstate!=formwindowstate.normal)
{
this.visible=true;
this.windowstate=formwindowstate.normal;
}
isfile=true;
newmsg.text=romefilename+"("+romefilel+")";
newmsg.bringtofront();
}
//传文件
private void linklabel1_linkclicked(object sender, system.windows.forms.linklabellinkclickedeventargs e)
{
if(linklabel1.text=="传文件")
{
t_send.height=80;
t_send.top=264;
linklabel1.text="不传文件";
}
else
{
t_send.height=120;
t_send.top=224;
linklabel1.text="传文件";
}
}
//打开文件
private void button4_click(object sender, system.eventargs e)
{
openfiledialog1.filter="所有文件|*.*|压缩文件|*.rar";
if(openfiledialog1.showdialog()==dialogresult.ok)
{
t_filep.text=openfiledialog1.filename;
}
}
//监听文件传送socket的线程——————功能:接收文件
public void listenport()
{
tcplistener listener=new tcplistener(2626);
listener.start();
socket s=listener.acceptsocket();
filestream filestream=new filestream(savepath,filemode.openorcreate,fileaccess.write);
networkstream stream=new networkstream(s);
//定义缓冲区
byte[] bb=new byte[1024];
//循环读socket流
int tt=0;
//进度条
processb.visible=true;
processb.backcolor=system.drawing.systemcolors.control;
int stepoff;
if(romefilel[romefilel.length-1]=='k')
stepoff=1024;
else
stepoff=1024*1024;
int totalste=int.parse(romefilel.substring(0,romefilel.length-1));
progressbar2.maximum=totalste;
progressbar2.step=totalste/20;
float recbytes=0;
while((tt=stream.read(bb,0,1024))!=0)
{//接收数据
filestream.write(bb,0,tt);
filestream.flush();
//更新进度条
recbytes+=(float)tt/stepoff;
progressbar2.value=(int)recbytes;
}
filestream.close();
processb.visible=false;
messagebox.show("文件接收完毕!");
}
//传送文件的线程————————功能:发送文件服务端
public void sendfile()
{
tcpclient serverclient=new tcpclient();
serverclient.connect(romeip,2626);
networkstream stream=serverclient.getstream();
//定义缓冲区
byte[] bb=new byte[1024];
//循环读文件
int number;
//进度条
processa.visible=true;
processa.backcolor=system.drawing.systemcolors.window;
int stepoff;
if(romefilel[romefilel.length-1]=='k')
stepoff=1024;
else
stepoff=1024*1024;
int totalste=int.parse(romefilel.substring(0,romefilel.length-1));
progressbar1.maximum=totalste;
progressbar1.step=totalste/20;
float sendedbytes=0;
while((number=sendfilestream.read(bb,0,1024))!=0)
{//向客户端发送流
stream.write(bb,0,number);
//刷新流
stream.flush();
//进度条
sendedbytes+=(float)number/stepoff;
progressbar1.value=(int)sendedbytes;
}
sendfilestream.close();
stream.close();
processa.visible=false;
messagebox.show("文件传送完毕!");
}
}
}
局域网qq(v1.4)
新闻热点
疑难解答