用VC++建了一个基于win32Application的局域网聊天室,但运行错误,求各位帮帮忙
#include "stdafx.h"#include "resource.h"
#include <VECTOR> //采用STL(模板库)
#include <algorithm>
#include <WINSOCK2.H> //调用winsock
#include <ASSERT.H>
#define BUFFER_SIZE 4096 //缓冲块大小
#define SERVER_MESSAGE WM_USER+100 //服务器SOCKET异步消息ID
#define CLIENT_MESSAGE WM_USER+101 //客户机SOCKET异步消息ID
//全局变量
SOCKET g_ListenSocket;//监听SOCKET(服务器)
std::vector<SOCKET> g_DataSockets;//所有和客户端相连的数据SOCKET(服务器)
SOCKET g ClientSocket;//客户端数据SOCKET(服务端)
BOOL g bActive; //在线标志(服务器和客户端)
std::string g_ChatWords; //在显示窗口显示所有文字
BOLL g_bClient; //客户端标志
BOLL ServerInit(HWND hwnd ,UINT port); //服务器初始化
BOLL ClientInit(HWND hwnd ,UINT port,const char* serverIP);//客户端初始化
int OnServerMessage(HWND hwnd,WPARAM wparam,LPARAM lparam);//服务器SOCKET异步消息处理函数
int OnClientMessage(HWND hwnd,WPARAM wparam,LPARAM lparam);//客户端SOCKET异步消息处理函数
void SendMessageTopeer(HWND HWND );//发送文字框的聊天内容
void Send(SOCKET sock,const char* buffer,int length);//具体发送函数(保证发送指定字节数内容)
void RefreshScreen(HWND hwnd);//刷新并滚动屏幕内容
void ExitChat(HWND hwnd);//结束当前会话
void GetErrorReason();//得到会话错误原因
//消息循环
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
//对话框的消息循环函数Wndproc定义如下:
//WM_COMMAND - process the application menu (处理应用程序菜单)
LERSULT CALLBACK WndProc(HWND hWnd,UINT message ,WPARAM wparam ,LPARAM lparam)
{
HWND subWnd;
char buffer[BUFFER_SIZE];
UINT port;
char serverIP[16];
switch (message)
{
case WM_INITDIALOG: //对话框初始化消息
{
//初始化socket栈
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
MessageBox(hWnd ,"Socket stack Error !","Error",IDOK);
return -1;
}
}
return TURE;
case WM_COMMAND: //各种控件消息
{
switch (LOWORD(wParam))
{
case IDOK: //“确定按钮”
case IDCANCEL: //"取消按钮"
EndDialog(hWnd,LOWORD(wParam));
break;
case IDC_CONNECT: //“连接服务器”按钮
{
subWnd=GetDlgItem(hWnd,IDC_LISTEN_PORT_C);
GetWindowText(subWnd,buffer,BUFFER_SIZE);
port=UINT(atoi(buffer));
subWnd=GetDlgItem(hWnd,IDC_SERVERIP);
GetWindowText(subWnd,buffer,BUFFER_SIZE);
strncpy(serverIP,buffer,16);
ClientInit(hWnd,port,serverIP);
}
break;
case IDC_LISTEN: //"建立服务器按钮"
{
subWnd=GetDlgItem(hWnd,IDC_LISTEN_PORT_S);
GetWindowText(subWnd,buffer,BUFFER_SIZE);
port=UINT(atoi(buffer));
ServerInit(hWnd,port);
}
break;
case IDC_INPUTEXT: //文字输入框
{
if(HIWORD(wParam))==EN_UPDATE) //这里响应EN_UODATE消息
{
//调用SendMessageToPeer处理用户输入
SendMessageToPeer(hWnd);
}
}
default;
break;
}
}
break;
case SERVER_MESSAGE: //服务器SOCKET异步信息
{
OnServeMessage(hWnd,wParam,lParam);
}
break;
case CLIENT_MESSAGE: //客户端SOCKET异步信息
{
OnClient
Message(hWnd,wParam,lParam);
}
break;
}
return 0;
}
//客户端初始化函数ClientInit
BOOT ClientInit(HWND,hWnd,UINT port,const char* serverIP)
{
sockaddr_in addr;
//退出上一次的会话
ExitChat(hWnd);
//设置客户端标志
g_bClient=TURE;
//判断IP是否有效(这里的IP是在IP地址控件中生成的,所以肯定有效
if(inet_addr(serverIP)==INADDR_NONE)
{
MessageBox(hWnd,"Invalid IP Address!","Warnning",IDOK);
return FALSE;
}
//创建面向连接的TCP/流方式socket
g_ClientSocket=socket(AF_INET,SOCK_STREAM,0);
assert(g_ClientSocket!=INVALID_SOCKET);
//设置客户端socket异步选择标志,被关联的消息ID是CLIENT_MESSAGE
//异步事件包括:连接、读、写、关闭和其他
WSAAsyncSelect(g ClientSocket,hWnd,CLIENT MESSAGE,FD READ|FD WRITE|FD CLOSE|FD CONNECT);
//设置服务器的端口和地址
addr.sin_family=AF_INET;//网络层采用网际协议(IP)
addr.sin_addr.s_un.s_addr=inet_addr(serverIP);//将标准点格式IP地址转换成long型网络地址
addr.sin port=htons(port);//将主机short型端口号转换成网络型
//连接服务器,异常在CLIENT_MESSAGE消息中捕获
connect(g ClientSocket,(sockaddr*)&addr,sizeof(addr));
//给出提示连接
g_ChatWords+="Connecting ....\r\n";
//刷新屏幕提示内容
RefreshScreen(hWnd);
return TURE;
}
//单击“建立服务器”按钮时,程序从子窗口IDC_LISTEN_PORT_S中提取监听端口,然后调用服务器初始化函数ServerInit
BOOL ServerInit(HWND hWnd,UINT port)
{
sockaddr_in addr;
char buffer[BUFFER_SIZE];
//退出上一次会话
ExitChat(hWnd);
//设置服务器端标志
g_bClient=FALSE;
//创建面向连接的TCP/流方式socket
g_ListenSocket=socket(AF_INET,SOCK_STREAM,0);
assert(g_ListenSocket!=INVALID_SOCKET);
//设置客户端socket异步选择标志,被关联的消息ID是SERVER_MESSAGE
//异步事件包括:接受 读 写 关闭 其他
WSAAsyncSelect(g ClientSocket,hWnd,CLIENT_MESSAGE,FD_ACCEPT|FD_READ|FD_WRITE|FD_CLOSE);
//设置监听消息
addr.sin_family=AF_INET;//网络层采用网际协议(IP)
addr.sin_addr.s_un.s_addr=INADDR_ANY;//任选本机某个网卡的IP地址(通常只有一个网卡)
addr.sin port=htons(port);//将主机short型端口号转换成网络型
//绑定监听socket
if(bind(g_ ListenSocket,(sockaddr*)&addr,sizeof(addr))==SOCKET_ERROR)
{
sprintf(buffer,"Port %d has been taken.Change another port.\r\n",port);
g_ChatWords+=buffer;
RefreshScreen(hWnd);
MessageBox(hWnd,"Binding Error","Warnning",IDOK);
return FALSE;
}
//监听
if(listen(g_ListenSocket,5)==SOCKET_ERROR) //“5”是指监听端口的并发链接数上限
{
strcpy(buffer,"Listen error.\r\n");
g_ChatWords+=buffer;
RefreshScreen(hWnd);
MessageBox(hWnd,"Listen Error","Warnning",IDOK);
return FALSE;
}
//给出服务器提示消息
g_ChatWords+="Server is listening....\r\n";
//刷新屏幕内容并滚动
RefreshScreen(hWnd);
//设置在线标志
g_bActive=TRUE;
return TURE;
}
//SendMessageToPeer定义如下:
SendMessageToPeer(HWND hWnd)
{
HWND subwnd;
char buffer[BUFFER_SIZE];
int i;
static int oldNumOFChars=0; //如果文本框中两次字符数目一致,则认为有回车键被按下
subwnd=GetDlgItem(hWnd,IDC_INPUTTEXT); //得到文本窗口句柄
GetWindowsText(subwnd,buffer,BUFFER_SIZE); //得到文本框内容
//如果本次内容长度和上次内容长度一致,则认为用户按下了回车键
if(oldNumOFChars!=strlen(buffeer)
{
oldNumOFChars=strlen(buffer);
return;
}
//清空文本框内容
SetWindowsText(subwnd," ");
//重置上一次内容长度
oldNumOFChars=0;
//如果当前不在线
if(!g_bActive)
{
g_ChatWords+=buffer;
g_ChatWords.erase(g_ChatWords.size(),1);
g_ChatWords+="(Hint: you are isolated now.)\r\n";
RefreshScreen(hWnd);
return;
}
//如果当前在线
strcat(buffer,"\r\n");
g_ChatWindows+=buffer;
//刷新屏幕内容
RefreshScreen(hWnd);
//如果当前是客户端,则发送文本内容到服务器
if(g_bClient)
{
Send(g_ClientSocket,buffer,strlen(buffer));
}
else //如果当前是服务器,则发送文本内容到所有客户机
{
for(i=0;i<=g_DataSocket.size();i++)
Send(g_DataSockets[i],buffer,strlen(buffer));
}
}
//Send函数的定义:
void Send(SOCKET sock,const char* buffer,int length)
{
int ret,i;
i=0;
while(length>0)
{
if(ret==0)
break;
else if(ret==SOCKET_ERROR)
{
g_ChatWords+="Error sending.\r\n";
break;
}
length-=ret;
i+=ret;
}
}
//在消息循环中调用的函数OnClientMessage定义如下:
int onClientMessage(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
char buffer[BUFFER_SIZE+1]; //recv函数返回的buffer是实际字符串长度,所以需要额外+1字节,用来填补NULL字符
int retCode;
//先检查lparam高字节,判断套接字是否有错误发生,宏WSAGETSELECTERROR用来检查错误消息
if(WSAGETSELECTERROR(lParam))
{
closesocket(g_ClientSocket);
strcpy(buffer,"Server has no response.\r\n");
g_ChatWords+=buffer;
RefreshScreen(hWnd);
g_bActive=FALSE;
return 0;
}
switch(WSAGETSELECTEVENT(L=lParam))
{
case FD_CONNCET: //连接消息
//给出成功连接的提示
g_ChatWords+="Successfully connected.\r\n";
//刷新屏幕内容
RefreshScreen(hWnd);
break;
case FD_READ:
//读消息
//接收数据
retCode=recv(g_ClientSocket,buffer,BUFFER_SIZE,0);
if(retCode!=SOCKET_ERROR)
{
buffer[retCode]=NULL;
g_ChatWords+=buffer;
}
else
GetErrorReason();
//刷新屏幕内容
RefreshScreen(hWnd);
break;
case FD_WRITE: //写消息
break;
case FD_CLOSE: //关闭消息
GetErrorReason();
closesocket(g_ClientSocket);
//提示用户服务器已经关闭会话
strcpy(buffer,"Server close session.Successfully long out.\r\n");
g_ChatWords+=buffer;
RefreshScreen(hWnd);
//设置离线标志
g_bActive=FALSE;
break;
}
return 0;
}
//在主程序的消息循环中调用的OnServerMessage函数定义如下:
int OnServerMessage(HWND hWnd,WPARAM wParam ,LPARAM lparam )
{
SOCKET socket;
int i,retCode,namelen;
char buffer[BUFFER_SIZE+1]; //recv函数返回的buffer是实际字符串长度,所以需要额外给出+1字节,用来填补NULL字符
std::vector<SOCKET>::iterator ite;
sockaddr_in name; //getpeername将会使用该地址结构
namelen=sizeof(name); //getpeername将会使用该长度变量
//先检查lparam高字节,判断套接字是否有错误发生,宏WSAGETSELECTERROR用来检查错误消息
if(WSAGETSELECTERROR(lParam))
{
//某个客户端粗暴地结束了会话,该会话socket的ID是由参数wParam标识的
getpeername((SOCKET)wParam,(sockaddr*)&name,&namelen);
//关闭会话socket
closesocket(SOCKET)wParam);
//将该会话socket从数据SOCKET数组中删除
ite=std::find(g_DataSockets.begin(),g_DataSockets.end(),(SOCKET)wParam);
assert(ite!=g_DataSockets.end());
g_DataSockets.erase(ite);
//向其他客户端发送该客户端失去联络的消息
sprintf(buffer,"Client %s: %d lost contact with us.\r\n",inet_nota (name.sin_addr),ntohs(name.sin_port));
for(i=0;i<g_DataSockets.size();i++)
{
Send(g_DataSockets[i],buffer,strlen(buffer));
//刷新屏幕内容‘
g_ChatWords+=buffer;
RefreshScreen(hWnd);
return 0;
}
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT: //连接消息
//接受客户端连接,并生成一个和客户端会话的数据socket
socket=accept(g_ListenSocket,NULL,NULL);
//得到客户端连接的IP地址和端口号(accept函数也可以实现该操作)
getpeername(socket,(sockaddr*)&name,&namelen);
//将该客户端登录的消息发送给其他客户端
sprintf(buffer,"A guest joins us.(%s:%d)\r\n",inet_ntoa(name.sin_addr),ntohs(name.sin_port));
g_ChatWords+=buffer;
for(i=0;i<g_DataSockets.size();i++)
Send(g_DataSockets[i],buffer,strlen(buffer));
//向该客户端发送欢迎词
sprintf(buffer,"welcome!(You ID is:%s:%d.")\r\n",inet_nota (name.sin_addr),noths(name.sin_port));
Send(socket,buffer,strlen(buffer));
//刷新屏幕内容
RefreshScreen(hWnd);
//把新建的数据socket加入到会话SOCKET数组中
g_DataSocket.push_back(socket);
break;
case FD_READ: //读消息
{
//读取某个客户端消息,该会话socket的ID是由参数wParam标识的
retCode=recv(SOCKET)wParam,buffer,BUFFER_SIZE,O);
buffer[retCode]=NULL;
//将接收到的消息发送给其他端客户
for(i=0;i<g_DataSockets.size();i++)
{
if(wParam!=g_DataSockets[i])
Send(g_DataSockets[i],buffer,strlen(buffer));
}
//刷新屏幕内容
g_ChatWords+=buffer;
RefreshScreen(hWnd);
}
break;
case FD_WRITE: //写消息
return 0;
case FD_CLOSE: //关闭消息
//某个客户端礼貌的关闭了socket,该会话socket的ID是由参数wParam标识的
getpeername((SOCKET)wParam,(sockaddr*)&name,&namelen);
//服务器也需要关闭会话Ssocket
closesocket((SOCKET)wParam);
//将该会话socket从数据SOCKET数组中删除
ite=std::find(g_DataSockets.begin(), g_DataSockets.end(),(SOCKET)wParam);
assert(ite!=g_DataSockets.end());
g_DataSockets.erase(ite);
//向其他客户端发送该客户端离开的消息
sprintf(bufferf,"Client %s:%d left.\r\n",inet_ntoa (name.sin_addr),nthos(name.sin_port));
for(i=0;i<g_DataSockets.size();i++)
Send(g_DataSockets[i],buffer,strlen(buffer));
//刷新屏幕内容
g_ChatWords+=buffer;
RefreshScreen(hWnd);
}
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
//标志当前为离线状态
g_bActive=FALSE;
//所有操作都在对话框中完成
DialogBox(hInstance,(LPCTSTR)IDD_CHAT_DIALOG,NULL,(DLGPROC) WndProc);
return 0;
}
}
void ExitChat(HWND hWnd)
{
int i;
char buffer[BUFFER_SIZE]; //如果当前在线,则需要结束当前会话
if(g_bActive) //在线标志
{
//如果是客户端,则只需要关闭当前连接
if(g_bClient)
{
closesocket(g_ClientSocket);
strcpy(buffer,"Successfully log out .\r\n");
g_ChatWords+=buffer;
RefreshScreen(hWnd);
}
else
{ //如果是服务器,则需要关闭监听socket,另外还需要将所有数据socket关闭
//向所有客户端告别
strcpy(buffer,"I will leave. Plsase clients log out ASAP.\r\n");
for(i=o;i<g_DataSockets.size();i++)
{
//发送完告别此后立即关闭连接
send(g_DataSockets[i],buffer,strlen(buffer),0);
closesocket(g_DataSocket[i]);
}
//清空连接SOCKET数组
g_DataSockets.clear();
//关闭监听socket
closesocket(g_ListenSocket);
strcpy(buffer,"Successfully close server.\r\n");
g_ChatWords+=buffer;
RefreshScreen(hWnd);
}
}
//设置离线标志
g_bActive=FALSE;
}
RefreshScreen(HWND hWnd)
{
HWND subWnd;
std::string::size_type pos;
int n;
subWnd=GetDlgItem(hWnd,IDC_SHOWTEXT);
SetWindowsText(subWnd,g_ChatWords.c_str());
n=0;
pos=0;
while((pos=g_ChatWords.find('\n',pos))!=std::string::npos)
{
pos++;
n++;
}
SendMessage(subWnd,EM_LINESCROLL,O,n);
}
void GetErrorReason()
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR) &LPMsgBuf,0,NULL);
g_ChatWords+=(chat *)lpMsgBuf;
g_ChatWords+="\r\n";
LocalFree(lpMsgBuf);
}
错误如下:
:\聊天室\聊天室.cpp(19) : error C2146: syntax error : missing ';' before identifier 'ClientSocket'
F:\聊天室\聊天室.cpp(19) : fatal error C1004: unexpected end of file found