1 recvfrom sendto的解释
if(-1 != sendto(sockMy, buf, sizeof(buf), 0, (SOCKADDR*)&addrFar, sizeof(SOCKADDR)))
参数依次为: 发送端socket 发送端缓冲区 发送端缓冲区大小 0 接收端地址 sizeof(SOCKADDR)
返回值 :为整型,如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR。
recvfrom(SockMy, BUF, BUF_SZ, 0, (SOCKADDR*)&AddrFar, &len);
参数意义 依次为 接收端socket 接收端缓冲区 接收端缓冲区大小 0 用来保存数据来源地址 len=sizeof(SOCKADDR)
返回值 :如果正确接收返回接收到的字节数,失败返回-1.
注意 初学者使用sendto的时候容易把接收端的xxx..sin_addr.S_un.S_addr 设置为INADDR_ANY 这是错误的 因为INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。 只能在发送端才可以使用INADDR_ANY(服务端客户端都可能是发送端) ,否则的话就无法判断我们要发送的地址是哪里。
另外我们常用inet_ntoa(addrTo.sin_addr) 这个函数来判断是否正确的地址 它是与inet_addr相反
2 线程相关
因为线程函数必须是 全局的 或者static的 如果定义为全局的 则我们无法让函数属于某个类 这时候我们只能将类的指针传递给此函数 如下
//创建接受消息线程
HANDLE hThread=CreateThread(NULL,0,RecvProc,this,0,NULL);
创建了一个线程 将this指针传递过去
DWORD WINAPI RecvProc(LPVOID lpParameter)
{
CChat *This = (CChat *)lpParameter;
return 0;
}
如上 我们将可以通过This使用类的成员。
通常都是定义为static的
3 全局变量定义的一种方法
假设工程名为520Chat 则在MFC自动生成的类CMy520ChatApp的头文件中添加 我们需要的全局变量 如int UserId 在构造函数中初始化
当使用全局变量时 添加 CMy520ChatApp *app = (CMy520ChatApp *)AfxGetApp(); 这句话
通过 app->UserId 便可以使用全局变量
4 CString转换成char*
CString theString;
.....................;
char* lpsz =(LPTSTR)(LPCTSTR)theString;
5 添加自定义消息
工作线程中不能使用UpdateData来更新主线程中的数据。界面的东西,最好就是用主线程(界面线程)去执行相应的操作。要想在子线程(工作线程)里执行界面线程的操作,最好是向主线程发送消息。因为MFC的CWnd用到了TLS,所以不是线程安全的。
MFC的窗口是线程相关的,每个窗口的HandleMap是储存在线程相关的堆栈里面的(thread-local-storage (TLS) ),那这样我就理解了为什么上面两句ASSERT会出错了,线程环境都切换了当然线程堆栈的数据也就不一样了.
解决方法:
在线程中发送自定义消息让主线程接收进行updatedata。
步骤:
1 在主线程对应头文件中 加入 #define WM_RECVDATA WM_USER+1
2 添加消息映射
BEGIN_MESSAGE_MAP(CChatDlg, CDialog)
..................
ON_MESSAGE(WM_RECVDATA,OnRecvData)//添加这一句
.................
END_MESSAGE_MAP() 3 在步骤1对应的头文件的
//{{AFX_MSG(CChatDlg)
..........
//}}AFX_MSG
中间加入 afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);
4 定义这个函数
void CChat::OnRecvData(WPARAM wParam,LPARAM lParam)
{
UpdateData(FALSE);
在线程中发送消息
::PostMessage(This->m_hWnd,WM_RECVDATA,0,NULL); 我把this指针传递过来给了This 所以用This直接调用主线程窗口的句柄