回 帖 发 新 帖 刷新版面

主题:[原创]VC bind()函数绑定问题

这是孙鑫那本VC++深入详解中的网络编程的一段代码,为什么绑定不能成功呢?请各位大侠帮忙看看???

if(!AfxSocketInit())//用来加载套接字库,进行版本协商,默认加载1.1版本套接字库
//还可以确保程序终止之前,调用::WSACleanup,终止套接字库的使用
{
    AfxMessageBox("加载套接字失败!");
    return FALSE;
}
需要加载头文件#include "AfxSock.h",将其写入stdafx.h当中。旧版本MSDN中没有写,记住。

初始化套接字:
BOOL CChatApp::InitInstance()
{
if(!AfxSocketInit())//用来加载套接字库,进行版本协商,程序结束时不需要调用WSACleanup()
{
    AfxMessageBox("加载套接字失败!");
    return FALSE;
}

在CCharDlg类中增加成员函数BOOL CChatDlg::InitSocket()和成员变量SOCKET::m_socket。在CChatDlg::InitDialog中调用InitSocket()。
BOOL CChatDlg::InitSocket()
{
m_socket=socket(AF_INET,SOCK_DGRAM,0);
if(INVALID_SOCKET==m_socket)
{
    AfxMessageBox("套接字创建失败");
    return FALSE;  
}//接收端需要绑定的某个IP地址和端口上。
SOCKADDR_IN addrSock;
addrSock.sin_family=AF_INET;
addrSock.sin_port=htons(6000);
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

int retval;
retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));
if(SOCKET_ERROR==retval)
{
    closesocket(m_socket);
    AfxMessageBox("绑定失败");
    return FALSE;
}
return TRUE;

retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));别忘记加&号
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);此处INADDR_ANY表示接收任意IP地址。

之后在BOOL CChatDlg::OnInitDialog()中调用BOOL CChatDlg::InitSocket(),这样初始化的工作才算完成。

所有与窗口有关的类都有一个数据成员m_hWnd,它保存了和这个类相关的窗口句柄

要调用类的成员函数,必须先产生一个对象,然后通过对象调用
如果把类中的成员函数声明为static,它就不属于对象,而直接属于类,然后就可以直接调用了。

在BOOL CChatDlg::OnInitDialog()中建立线程,首先要构造结构体以给CreateThread()传递两个参数,但只能传递一个指针,则需要定义一个结构体:
struct RECVPARAM
{
SOCKET sock;
HWND hwnd;
};//在CChatDialog头文件中定义结构体。

在OnInitDialog中建立线程:
RECVPARAM *pRecvParam=new RECVPARAM;
pRecvParam->hwnd=m_hWnd;//初始化对话框句柄,也可以是编辑框句柄 
pRecvParam->sock=m_socket;、
HANDLE hThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);//创建线程
CloseHandle(hThread);//关闭线程句柄。

利用成员函数作为线程函数,需要先产生对象才能调用其成员函数,可以将其声明为静态函数,这就不需要先产生对象才能调用其成员函数了
接下来创建线程函数,代码如下:
static DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)
{
SOCKET sock=((RECVPARAM*)lpParameter)->sock;
HWND hwnd=((RECVPARAM*)lpParameter)->hwnd;

SOCKADDR_IN addrFrom;
int len=sizeof(SOCKADDR);

char recvBuf[200];
char tempBuf[400];

int retval;
while(TRUE)
{
    retval=recvfrom(sock,recvBuf,200,NULL,(SOCKADDR*)&addrFrom,&len);
    if(SOCKET_ERROR==retval)
     break;
    sprintf(tempBuf,"%s said:%s",inet_ntoa(addrFrom.sin_addr),recvBuf);
    ::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);
//通过发送消息方式把数据传给对话框,
//传递一个自定义消息WM_RECVDATA,在CChatDialog头文件中定义消息的值。
//将数据通过lParam进行传递。
}

return 0;
}
inet_ntoa()将点分十进制转化为字符串。
在ChatDlg.h中要把线程函数设为static,另一种方法是把线程函数定义为全局线程函数。

实现消息响应函数步骤:
定义消息WM_RECVDATA:#define WM_RECVDATA    WM_USER+1
做一个消息相应函数原形的声明:
afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);

在元文件中
BEGIN_MESSAGE_MAP(CChatDlg, CDialog)
定义消息映射
ON_MESSAGE(WM_RECVDATA,OnRecvData)
实现消息响应函数:
END_MESSAGE_MAP()


void CChatDlg::OnRecvData(WPARAM wParam,LPARAM lParam)
{
CString str=(char*)lParam;
CString strTemp;
GetDlgItemText(IDC_EDIT_RECV,strTemp);
str+="\r\n";
str+=strTemp;
SetDlgItemText(IDC_EDIT_RECV,str);
}

最后为按钮添加消息实现代码:
void CChatDlg::OnSend()
{
DWORD dwIP;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->GetAddress(dwIP);

SOCKADDR_IN addrTo;
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(6000);

CString strSend;
GetDlgItemText(IDC_EDIT_SEND,strSend);

sendto(m_socket,strSend,strSend.GetLength()+1,0,
    (SOCKADDR*)&addrTo,sizeof(SOCKADDR));
SetDlgItemText(IDC_EDIT_SEND,"");    //把发送框设为空白
}

回复列表 (共1个回复)

沙发

用WSAGetLastError查一下吧.
在MSDN中以索引的方式搜索bind function.里面讲得很清楚.

我来回复

您尚未登录,请登录后再回复。点此登录或注册