| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 838 人关注过本帖
标题:用VC++建了一个基于win32Application的局域网聊天室,但运行错误,求各位帮 ...
只看楼主 加入收藏
高原熊狮
Rank: 1
来 自:北京
等 级:新手上路
帖 子:2
专家分:0
注 册:2011-5-16
结帖率:0
收藏
已结贴  问题点数:20 回复次数:3 
用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
搜索更多相关主题的帖子: 聊天室 局域网 服务器 服务端 客户机 
2011-05-16 21:47
记叙、继续
Rank: 4
等 级:业余侠客
帖 子:56
专家分:226
注 册:2011-5-17
收藏
得分:20 
貌似我们c语言论坛没有赛班活跃,小弟对c语言很有兴趣但自己没有入门,希望大家多发点基础的,谢谢拉!
2011-05-17 19:21
高原熊狮
Rank: 1
来 自:北京
等 级:新手上路
帖 子:2
专家分:0
注 册:2011-5-16
收藏
得分:0 
先通过书把C语言最基础的知识了解清楚,然后再试着编程,把编程中遇到的问题发到论坛上,大家一块看看咋回事,到时你在重新试一下。这样的话,学起来效果比较好。
2011-05-17 19:35
记叙、继续
Rank: 4
等 级:业余侠客
帖 子:56
专家分:226
注 册:2011-5-17
收藏
得分:0 
恩,谢谢楼上,我有学到拉
2011-05-22 12:44
快速回复:用VC++建了一个基于win32Application的局域网聊天室,但运行错误,求各 ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.079492 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved