Win32 SDK 实现UDP聊天室程序(二)

来源:互联网 发布:java cronexpression 编辑:程序博客网 时间:2024/05/22 01:39

          好了。上一节讲套接字的初始化和接收端线程的编写。这一节我们来写发送端。

发送端的主要功能是将发送编辑器里面的数据发送过去。我们用一个函数来实现。

void SendData(HWND hwnd)

函数首先还是创建一个网络地址。初始化后。得到姓名编辑框的名字和IP编辑框的IP;

然后将数据和 姓名发送给接收端线程。

函数实现如下:

void SendData(HWND hwnd)
{
 TCHAR cResult[50];
 TCHAR sendBuf[256];//作为单次传输不的超过256. 也就是1K.若要大于它就要分割数据。采writefile和readfile来实现。
 TCHAR cResultU[50];
 TCHAR cResultI[50];

// 这里我们先得到IP编辑框里面的内容。
 GetDlgItemText(hwnd,IDC_EDT_ADDR,cResult,sizeof(cResult));
 

//初始化发送端的网络地址结构。还是跟前面一样。

//但是我们前面的地址由于是服务端可以接收多人的数据。所以我们用INSOCK_ANY来初始化。

//但是这里我们要先得到对方IP.再赋给网络地址结构。
 SOCKADDR_IN addrTo;

//在这里我开始没有用(char*)来转换得不到IP,后来我用MessageBox在它的前面输出后居然可以了。所以我在下面加上(char*)

//就成功了。所以我们经常可以采用MessageBox来看结果。
 addrTo.sin_addr.S_un.S_addr = inet_addr((char*)cResult);//记得强制转化为char*
 addrTo.sin_family = AF_INET;
 addrTo.sin_port = htons(port);
   //下面是判断用户是否输入了名字和IP.
   GetDlgItemText(hwnd,IDC_EDT_USE,cResultU,sizeof(cResultU));
   GetDlgItemText(hwnd,IDC_EDT_ADDR,cResultI,sizeof(cResultI));
 if(0 == strcmp(cResultU,""))
 {
  MessageBox(hwnd,TEXT("请登陆用户名和IP!"),TEXT("错误!"),MB_OK);
  return ;
 }
 if(0 == strcmp(cResultI,""))
 {
  MessageBox(hwnd,TEXT("请登陆用户名和IP!"),TEXT("错误!"),MB_OK);
  return ;
 }

//得到发送编辑框里面的数据。
 GetDlgItemText(hwnd,IDC_EDT_SEND,sendBuf,sizeof(sendBuf));
 if(strcmp(sendBuf,"") == 0)
 {
  MessageBox(hwnd,TEXT("不能发送看空信息!"),TEXT("错误"),MB_OK);
  return ;
 }
 int retsend;

//这里UDP的我们采用sendto来发送数据。TCP的采用send。

参数跟recvfrom一样。可以对照来学习。
 retsend = sendto(m_socket,sendBuf,sizeof(sendBuf),0,
         (SOCKADDR*)&addrTo,sizeof(addrTo));
    if(retsend <= 0)
    {
     MessageBox(hwnd,TEXT("发送失败!"),TEXT("失败"),MB_OK);
    }
    SetDlgItemText(hwnd,IDC_EDT_SEND,"");//最后清空发送编辑框。
}

  完工!发送端的函数就这么简单。最基本的聊天程序原理都完了。后面的就是自己怎么去加一些自己喜欢的东西啦。

像我写的。用户名和IP必须在另一个对话框中来填写。是不允许在主对话框中直接的写。所以这就涉及到创建子对话框的内容了。在这里我只是简单的说说。因为主要还是讲网络编程的啦。

首先创建对话框我们有两个函数可以实现。

 

 1.对话框模板资源创建一个无模式的对话框

  HWND CreateDialog(HINSTANCE hlnstance,LPCTSTR lpTemplate,HWND hWndParent,DLGPROC IpDialogFunc);

2. 根据对话框模板资源创建一个模态的对话框:

 int DialogBox(HINSTANCE hlnstance,LPCTSTRIpTemplate,HWND hWndParent,DLGPROC IpDialogFunc);

关于模式和无模式的观念。这里就不讲了。大家可以参考其他书籍。其实你看两个函数创建的参数都一样。

我这里采用的是模式对话框。

           // 调用应用程序实例句柄。这个函数前面已经用过。
              HINSTANCE appInstance = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
              //创建子对话框,
              DialogBox(appInstance,MAKEINTRESOURCE(IDD_ABOUT),hwnd,(DLGPROC)DialogProc);

  第一个是实例的句柄。第二个是资源,我们采用MAKEINTRESOURCE来加载。第三个你要创建子窗口的父窗口的句柄。

当然如果你没有父窗口的话。直接NULL就可以了。最后一个参数是回调函数。也就是程序处理函数。大多是处理消息的。

其实他跟你开始建立的窗口处理函数是一样的。也没什么好讲的。

BOOL CALLBACK DialogProc(HWND hwndDlg,UINT UMsg,WPARAM wParam,LPARAM IParam)
{
 TCHAR cResultU[50];
 TCHAR cResultI[50];
 switch(UMsg)
 {
  case WM_INITDIALOG:
  {
     BOOL IsChecked = SendMessage(GetDlgItem(hwndDlg,IDC_CHK),BM_GETCHECK,0,0);
           if(IsChecked)
           {
                      SetWindowText(GetDlgItem(hwndDlg,IDC_EDT1),TEXT("流浪的心"));
                      SetWindowText(GetDlgItem(hwndDlg,IDC_EDT2),TEXT("127.0.0.1"));
                      EnableWindow(GetDlgItem(hwndDlg,IDC_EDT1),FALSE);
                      EnableWindow(GetDlgItem(hwndDlg,IDC_EDT2),FALSE);
                     
        
            }
  }
       break;
  case WM_COMMAND:
    {
     //鼠标点击消息。
      int id = wParam;
      switch(id)
      {
       case IDC_CHK:
          {
             BOOL IsChecked = SendMessage(GetDlgItem(hwndDlg,IDC_CHK),BM_GETCHECK,0,0);
             if(IsChecked)
             {
                        SetWindowText(GetDlgItem(hwndDlg,IDC_EDT1),TEXT("侯永华"));
                        SetWindowText(GetDlgItem(hwndDlg,IDC_EDT2),TEXT("127.0.0.1"));
                        EnableWindow(GetDlgItem(hwndDlg,IDC_EDT1),FALSE);
                        EnableWindow(GetDlgItem(hwndDlg,IDC_EDT2),FALSE);
                      
                      }
                      else
                      {
                       EnableWindow(GetDlgItem(hwndDlg,IDC_EDT1),TRUE);
                        EnableWindow(GetDlgItem(hwndDlg,IDC_EDT2),TRUE);
                        SetWindowText(GetDlgItem(hwndDlg,IDC_EDT1),TEXT(""));
                  SetWindowText(GetDlgItem(hwndDlg,IDC_EDT2),TEXT(""));
                      }
          }
         break;
       case IDC_BTNOK:
        {
         
        GetDlgItemText(hwndDlg,IDC_EDT1,cResultU,sizeof(cResultU));
        GetDlgItemText(hwndDlg,IDC_EDT2,cResultI,sizeof(cResultU));
        if(0 == strcmp(cResultU,""))
        {
         MessageBox(hwndDlg,TEXT("用户名不能为空!"),TEXT("错误!"),MB_OK);
         return FALSE;
        }
        if(0 == strcmp(cResultI,""))
        {
         MessageBox(hwndDlg,TEXT("用户名不能为空!"),TEXT("错误!"),MB_OK);
         return FALSE;
        }
        //再这里不知道为什么我用GetParent(hwndDlg)得不到父句柄 ?
        //我现在只能用声明一个全局的父对话框句柄来实现。
        SetWindowText(GetDlgItem(Hwnd,IDC_EDT_USE),cResultU);
        SetWindowText(GetDlgItem(Hwnd,IDC_EDT_ADDR),cResultI); 
        EndDialog(hwndDlg,0);
         }
          break;
            case IDC_BTNCAN:
                 EndDialog(hwndDlg,0);
                 break;
      }
    }
    break;
    case WM_DESTROY:
         EndDialog(hwndDlg,0);
      break;
       default:
      break;
 }
 return 0;//记得返回为零
}
好了。窗口处理 函数也讲完了。比较注意的是两个窗口间的传输数据的问题。还有个窗口控件句柄的问题要理清除。

不要掉混了 。

还有菜单的处理。这里就讲两个函数。一个是标记是否复选:CheckMenuItem,和禁用EnableMenuItem函数。

以前我以为可以用EnableWindow来实现。发现不可以。呵呵。是这连个函数。关于具体的用法大家可以看看MSDN。

很好用的函数哦,你以后会经常用到的。

  OK!写完了 。由于是初学有不对的地方希望能告诉我。我写这个主要是对自己所学的做一个总结。看看自己到底学会了什么。有一种温习的作用。而且可以加深自己对知识的理解。明天写多功能记事本程序实现总结。j

 

 

原创粉丝点击