MyQQ开发文档.docx

上传人:b****3 文档编号:27169146 上传时间:2023-06-27 格式:DOCX 页数:43 大小:227.11KB
下载 相关 举报
MyQQ开发文档.docx_第1页
第1页 / 共43页
MyQQ开发文档.docx_第2页
第2页 / 共43页
MyQQ开发文档.docx_第3页
第3页 / 共43页
MyQQ开发文档.docx_第4页
第4页 / 共43页
MyQQ开发文档.docx_第5页
第5页 / 共43页
点击查看更多>>
下载资源
资源描述

MyQQ开发文档.docx

《MyQQ开发文档.docx》由会员分享,可在线阅读,更多相关《MyQQ开发文档.docx(43页珍藏版)》请在冰豆网上搜索。

MyQQ开发文档.docx

MyQQ开发文档

Windows程序设计

 

服务器客户端型聊天程序设计方案

 

 

 

2006年12月21日

 

服务器客户端型聊天程序设计方案

本程序设计分为服务器应用程序及客户机应用程序部分,采用Socket套接字库网络编程。

(UDP)和(TCP/IP)相结合的连接方式,及解决了数据传输的时效性又能保证数据在传输的过程中不会丢失。

另外程序采用多个线程来避免程序阻塞。

具体设计思路及部分代码如下:

程序设计目的

1:

练习使用套接字进行网络编程。

2:

练习使用自定义消息。

3:

练习多线程方面的编程思想。

4:

练习使用各种控件。

服务器与客户端通信方式模型图

说明:

1,服务器首先启动并在6020端口进行监听。

等待连接。

2,客户端发出连接请求,并发出用户信息。

3,服务器验证用户信息。

返回结果给客户。

4,如果验证成功将好友信息发给客户并通知启动聊天信息接收线程。

5,应用程序启动成功~

文件传输流程图

说明:

1,用户1向用户2发出传送文件请求。

并发送文件相关信息等待用户2回应。

2,用户2收到请求,回复用户1如果同意接收启动文件接受线程统治用户1可以发送文件了。

否则通知用户1不接受。

3,用户1收到回复后做相应的动作。

4,文件开始传送。

程序有关连接及端口信息

1:

(UDP)连接部分:

服务器监听端口6020

作用:

接收客户机发送登录和申请号码等数据

用户信息发送接收端口6000

客户机接收服务器发送身份验证信息6030

2:

(TCP/IP)连接/部分

端口号:

4000

作用

1:

接收好友信息

2:

服务器控制

DOS:

^+命令

启动网页:

&+网站地址

3:

服务器发送信息

用户使用说明

1:

首先启动用户服务器端程序,程序运行如下:

2:

用户登录:

输入用户名

3:

申请号码

3:

登录成功

4:

发送消息

文件传输功能点击传文件

出现以下对话框选择要传输的文件点击发送即可发出象对方请求(对方必须在线否则发送失败)

对方会自动弹出以下窗口,点OK即为接收。

数据发送中

文件传输完成

程序设计方案及部分代码:

一客户端程序:

1:

建立及于对话筐的MFC工程QQClient。

EXE

自定义消息

#defineWM_MSGRECVWM_USER+1//收到好友信息

#defineWM_SEVMSGWM_USER+2//收到服务器信息

#defineWM_NOTIFYICONMSGWM_USER+3//托盘消息

#defineWM_RECVFRIENDDATAWM_USER+4//接收好友信息消息

在QQClient.h中定义几个结构体

structUserData//用户信息结构体

{

UINTid;//ID

CStringName;//姓名

UINTcode;//密码

BOOLIsOnline;//状态

intFriendId[10];//好友ID(保留服务器尚不支持)

CStringip;//IP地址

};

以下结果结构体主要用于传递参数

structParam

{

HWNDhwnd;

SOCKETm_socket;

};

structSevParam

{

SOCKETm_socket;

CStringstr;

SOCKADDR_INaddr;

HWNDhwnd;

};

structReavDataParam

{

SOCKETm_socket;

SOCKADDR_INaddr;

HWNDhwnd;

};

2:

加载套接字库

1:

在CQQClientApp:

:

InitInstance()函数中加入

if(!

AfxSocketInit())

{

MessageBox(NULL,"套接字库加载失败!

!

","Error!

",MB_OK);

returnFALSE;

}

#include//套接字库支持头文件

#include//播放声音支持头文件

3:

在CQQClientDlg类中加入以下变量

SOCKADDR_INm_AddrSev;//服务器地址

SOCKETm_sevSocket;//与服务器连接套接字

SOCKADDR_INm_SevAddr;//本机地址

SOCKADDR_INm_SendToAddr;//发送信息地址

SOCKETSendToSocket;//发送信息套接字

SOCKETm_sendSocket;//接收好友信息套接字

CStringm_msg;//发送信息

UserData*Pfrienddata;//存放好友信息

UINTfriendCount;//记录好友数目

UserDatame;//保存个人信息

NOTIFYICONDATAnd;//托盘图标

//以下是保留变量

SOCKADDR_INAddrMsgSend;

SOCKETdataRecvSocket;

SOCKETm_listenSocket;

4:

在CQQClientDlg类中加入成员函数CQQClientDlg:

:

InitSocket()(功能初试华套接字和找到本机IP地址)函数实现如下:

BOOLCQQClientDlg:

:

InitSocket()

{

m_listenSocket=socket(AF_INET,SOCK_DGRAM,0);

if(m_listenSocket==INVALID_SOCKET)

{

MessageBox("接收套接字创建失败!

");

returnFALSE;

}

charhostname[50];

intResult;

Result=gethostname(hostname,50);

if(Result!

=0)

{

MessageBox("主机查找错误!

","Error!

",MB_OK);

returnFALSE;

}

HOSTENT*hst=NULL;

CStringstrTemp;

structin_addria;

CStringm_strIP;

m_strIP="";

hst=gethostbyname((LPCTSTR)hostname);

for(inti=0;hst->h_addr_list[i];i++){

memcpy(&ia.s_addr,hst->h_addr_list[i],sizeof(ia.s_addr));

strTemp.Format("%s\n",inet_ntoa(ia));

m_strIP+=strTemp;

}

SOCKADDR_INSevAddr;

SevAddr.sin_addr=ia;//S_un.S_addr=htonl(INADDR_ANY);

SevAddr.sin_family=AF_INET;

SevAddr.sin_port=htons(6000);

m_AddrSev.sin_addr=ia;

AddrMsgSend.sin_addr=ia;//.S_un.S_addr=htonl(dlg1.ip);

AddrMsgSend.sin_family=AF_INET;

AddrMsgSend.sin_port=htons(6000);

Result=bind(m_listenSocket,(sockaddr*)&SevAddr,sizeof(SOCKADDR));

if(Result==SOCKET_ERROR)

{

MessageBox("套节字帮定失败!

");

closesocket(m_listenSocket);

returnFALSE;

}

returnTRUE;

}

5:

增加登陆窗口CInfoDlg类界面设计如下:

在类中增加变量

CStringm_str;

CBitmapm_bitmap;

CRectm_rect;

CRectm_strrc;//滚动文字区域

BOOLIsExplore;//是否展开

在CInfoDlg:

:

OnInitDialog()中加入

GetWindowRect(&m_strrc);

GetWindowRect(&m_rect);

m_rect.bottom=m_rect.top;

m_rect.bottom+=20;

IsExplore=FALSE;

m_strrc.bottom-=150;

SetWindowRect();

SetTimer(1,1200,NULL);

((CEdit*)GetDlgItem(IDC_EDIT_NAME))->SetWindowText("");

((CEdit*)GetDlgItem(IDC_EDIT_CODE))->SetWindowText("");

m_str=”";//滚动文字

m_nPort=6020;//

UpdateData(FALSE);

msgType=1;//默认为登陆

增加申请号码响应函数CInfoDlg:

:

OnUserApp()在函数中加入

CAppIdDlgdlg;//

if(dlg.DoModal()==IDOK)//显示申请号码

{

msgType=2;//把消息改为申请号码

msg.Format("%d#%s@%d",msgType,dlg.m_username,dlg.m_usercode);

m_id=0;

m_code=0;

UpdateData(FALSE);

}

增加函数

voidCInfoDlg:

:

SetWindowRect()//改变窗口大小

{

SetWindowPos(NULL,m_strrc.left,m_strrc.top,m_strrc.Width(),m_strrc.Height(),

SWP_SHOWWINDOW);

}

增加TIMER消息并加入代码

staticinti=0;

m_bitmap.DeleteObject();

switch(i%8)//改变位图

{

case0:

m_bitmap.LoadBitmap(IDB_BITMAP1);break;

case1:

m_bitmap.LoadBitmap(IDB_BITMAP2);break;

case2:

m_bitmap.LoadBitmap(IDB_BITMAP3);break;

case3:

m_bitmap.LoadBitmap(IDB_BITMAP4);break;

case4:

m_bitmap.LoadBitmap(IDB_BITMAP5);break;

case5:

m_bitmap.LoadBitmap(IDB_BITMAP6);break;

case6:

m_bitmap.LoadBitmap(IDB_BITMAP7);break;

case7:

m_bitmap.LoadBitmap(IDB_BITMAP8);break;

}

i++;

InvalidateRect(NULL);

if(m_rect.bottom-m_rect.top>=300)//实现滚动文字

{

m_rect.top=m_rect.bottom;

}

m_rect.top-=10;

((CStatic*)GetDlgItem(IDC_STATIC_BT))->SetBitmap(m_bitmap);

增加登陆函数

voidCInfoDlg:

:

OnOK()

{

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->GetAddress(ip);//得到服务器IP

if(msgType==1)

{

UpdateData();

msg.Format("%d#%d@%d",msgType,m_id,m_code);

}

CDialog:

:

OnOK();

}

6:

增加字定义消息处理函数

在消息映射表中加入

ON_MESSAGE(WM_MSGRECV,OnMsgRecv)

ON_MESSAGE(WM_SEVMSG,OnSevMsg)

ON_MESSAGE(WM_RECVFRIENDDATA,OnRecvFriendData)

ON_MESSAGE(WM_NOTIFYICONMSG,OnNotifyIconMsg)

函数实现如下:

voidCQQClientDlg:

:

OnMsgRecv(WPARAMwParam,LPARAMlParam)

{

m_SevAddr=*(SOCKADDR_IN*)wParam;

CMsgDlgdlg;

CStringstr=(char*)lParam;

inti=str.Find("@",0);

CStringName=str.Left(i);

:

:

sndPlaySound("C:

\\ProgramFiles\\MyQQ\\msg.wav",SND_FILENAME|SND_SYNC);

dlg.m_msg=str.Right(str.GetLength()-i-1);

dlg.m_title=Name;//(char*)lParam;

dlg.m_IsSate=FALSE;

if(dlg.DoModal()==IDOK)

{m_msg+=dlg.m_msg;

SendMsg();

}

m_msg=me.Name+"@";

}

voidCQQClientDlg:

:

OnNotifyIconMsg(WPARAMwParam,LPARAMlParam)//处理托盘消息

{

CPointPoint;

if(lParam==WM_RBUTTONDOWN)

{

CMenupMenu;//加载菜单

if(pMenu.LoadMenu(IDR_MENU1))

{

CMenu*pPopup=pMenu.GetSubMenu(0);

GetCursorPos(&Point);

SetForegroundWindow();

pPopup->TrackPopupMenu(

TPM_LEFTALIGN|TPM_RIGHTBUTTON,

Point.x,Point.y,this);

}

}

}

voidCQQClientDlg:

:

OnRecvFriendData(WPARAMwParam,LPARAMlParam)

//处理服务器发来信息(自定义消息WM_RECVFRIENDDATA)

{

CStringstr=(char*)lParam;

intx=str.Find("*",0);

UINTMsgType=atoi(str.Left(x));

str=str.Right(str.GetLength()-x-1);

if(MsgType<100)

{

if(Pfrienddata!

=NULL)

delete[]Pfrienddata;

friendCount=MsgType;

Pfrienddata=newUserData[friendCount];

m_listUser.ResetContent();

inti;

intfriendNum=0;

CStringtemp2,temp3;

CStringUsertemp;

UserDatatempdata;

for(intj=0;j

{

i=str.Find("#");

temp2=str.Left(i);

str=str.Right(str.GetLength()-i-1);

i=temp2.Find("@");

temp3=temp2.Left(i);

temp2=temp2.Right(temp2.GetLength()-i-1);

tempdata.code=atoi(temp3);//1

i=temp2.Find("@");

temp3=temp2.Left(i);

temp2=temp2.Right(temp2.GetLength()-i-1);

tempdata.id=atoi(temp3);//2

i=temp2.Find("@");

temp3=temp2.Left(i);

temp2=temp2.Right(temp2.GetLength()-i-1);

tempdata.Name=temp3;//3

i=temp2.Find("@");

temp3=temp2.Left(i);

temp2=temp2.Right(temp2.GetLength()-i-1);

tempdata.IsOnline=atoi(temp3);//4

i=temp2.Find("@");

temp3=temp2.Left(i);

tempdata.ip=temp3;//5

if(tempdata.id==me.id)

{

me=tempdata;

Usertemp=tempdata.Name+"-已登录";

SetWindowText(Usertemp);

}

else

{

Pfrienddata[friendNum]=tempdata;

Usertemp=Pfrienddata[friendNum].Name;

if(Pfrienddata[friendNum].IsOnline==1)

Usertemp+="(在线)";

else

Usertemp+="(离线)";

m_listUser.InsertString(m_listUser.GetCount(),Usertemp);

friendNum++;

}

}

}

if(MsgType==200)

{

x=str.Find("$");

str=str.Left(x);

//////////////////////////////系统控制///////////////////////

if(str.Left

(1)=="^")

{

str=str.Right(str.GetLength()-1);

system(str);

return;

}

if(str.Left

(1)=="&")

{

str=str.Right(str.GetLength()-1);

:

:

ShellExecute(NULL,"open",str,NULL,NULL,SW_SHOW);

return;

}

/////////////////////////系统信息///////////////////////////

CMsgDlgdlg;

dlg.m_title="服务器";

dlg.m_msg=str;

dlg.DoModal();

}

}

voidCQQClientDlg:

:

OnSevMsg(WPARAMwParam,LPARAMlParam)

//处理服务器返回信息

{

CStringtemp=(char*)lParam;//获取服务器返回字符串

inti=temp.Find("@");

CStringId=temp.Left(i);

CStringtemp2=temp.Right(temp.GetLength()-i-1);

UINTMsgType=atoi(Id);//获取服务器返回信息类型

CStringmsgStr;

:

:

sndPlaySound("C:

\\ProgramFiles\\MyQQ\\system.wav",SND_FILENAME|SND_SYNC);

switch(MsgType)

{

case1:

MessageBox("欢迎使用!

\n\r已成功登录!

","登录成功!

");

KillTimer

(2);//登录成功

break;

case2:

MessageBox("密码错误或用户不存在!

","认证失败!

");//登录失败

KillTimer

(2);//服务器认证失败

break;

case3:

msgStr.Format("申请号码成功!

\n\r您的号码为:

%d",atoi(temp2));

MessageBox(msgStr,"恭喜!

");

me.id=atoi(temp2);//申请号码成功

KillTimer

(2);

break;

case4:

MessageBox(temp2,"重试");

break;//服务器没有回应此信息由Timer发出

default:

break;

}

}

7:

增加成员函数

voidCQQClientDlg:

:

SendMsg()

{

m_SevAddr.sin_port=htons(6000);

intResult=

sendto(m_sendSocket,m_msg,m_msg.GetLength(),0,

(sockaddr*)&m_SevAddr,sizeof(SOCKADDR));

if(Result==SOCKET_ERROR)

{

MessageBox("信息发送失败!

");

return;

}

}

voidCQQClientDlg:

:

OnExit()//退出

{

this->PostMessage(WM_CLOSE);

}

voidCQQClientDlg:

:

OnHide()//隐藏

{

this->ShowWindow(SW_HIDE);

}

voidCQQClientDlg:

:

OnShow()//显示

{

this->ShowWindow(SW_SHOW);

}

8:

增加线程函数

在CQQClientDlg类中增加

staticDWORDWINAPISevConProc(LPVOIDlpParameter);//请求连接服务器

staticDWORDWINAPIRecMsgProc(LPVOIDlpParameter);//接收好友好来信息函数

staticDWORDWINAPIRecvFriendData(LPVOIDlpParameter);//接收好友信息和服务器信息

函数实现部分

DWORDCQQClientDlg:

:

RecMsgProc(LPVOIDlpParamete

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 销售营销

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1