当前位置:首页 > MFC下CSocket编程详解
return 0; }
//绑定端口
if (!aSocket.Bind(nPort)) ...{
char szError[256] = ...{0};
sprintf(szError, \
AfxMessageBox(szError);
return 1; }
3) SDK 下的服务器端代码 //子线程函数
unsigned int StartServer(LPVOID lParam) ...{
//初始化Winsock, AfxSocketInit() 也是封装了这些语句, 不过 AfxSocketInit() 所做的事比这里多些
WSADATA wsaData;
//Winsock 的版本, 建议用1.1 ,兼容性好
WORD wVersionRequested = MAKEWORD(1, 1);
int nResult = WSAStartup(wVersionRequested, &wsaData); if (nResult != 0) ...{
return 1; }
//-----------------------------------------------------
m_exit = false;
CServerDlg *aDlg = (CServerDlg *)lParam;
CString strPort;
aDlg->GetDlgItemText(IDC_EDIT_PORT, strPort);
UINT nPort = atoi(strPort);
//socket------------------------------------------------
//接口对象
SOCKET aSocket, serverSocket;
//寻址相关结构
sockaddr_in serverSockaddr;
memset(&serverSockaddr, 0, sizeof(serverSockaddr));
aSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (aSocket == INVALID_SOCKET) ...{
char szError[256] = ...{0};
sprintf(szError, \
AfxMessageBox(szError);
return 1; }
//注意,该处非常重要,取值的正确与否决定关闭scoket后端口是否能正常释放 BOOL bOptVal = TRUE; int bOptLen = sizeof(BOOL);
//设置 socket 选项, SOL_SOCKET 和 SO_REUSEADDR 一起使用, 并且后面的参数如上,
关闭scoket后端口便能正常释放
setsockopt(aSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, bOptLen);
//寻址相关结构
sockaddr_in aSockaddr;
memset(&aSockaddr,0,sizeof(aSockaddr));
aSockaddr.sin_family = AF_INET;
aSockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
aSockaddr.sin_port = htons((u_short)nPort);
//绑定: 注意参数的类型转换
if(bind(aSocket,(sockaddr *)&aSockaddr, sizeof(aSockaddr)) == SOCKET_ERROR) ...{
char szError[256] = ...{0};
sprintf(szError, \
AfxMessageBox(szError);
return 1; }
//监听
if(listen(aSocket, 10) == SOCKET_ERROR) ...{
char szError[256] = ...{0};
sprintf(szError, \
AfxMessageBox(szError);
return 1; }
CString strText;
aDlg->GetDlgItemText(IDC_EDIT_LOG, strText);
strText += \
aDlg->SetDlgItemText(IDC_EDIT_LOG, strText);
while(!m_exit) ...{
//接收外部连接, 非阻塞
serverSocket = accept(aSocket, (sockaddr *)&serverSockaddr, 0);
if(serverSocket == INVALID_SOCKET) ...{
continue; } else
...{
char szRecvMsg[256] = ...{0}; char szOutMsg[256] = ...{0};
//接收客户端内容: 阻塞
recv(serverSocket, szRecvMsg, 256, 0);
sprintf(szOutMsg, \
aDlg->GetDlgItemText(IDC_EDIT_LOG, strText);
strText += szOutMsg;
aDlg->SetDlgItemText(IDC_EDIT_LOG, strText);
//发送内容给客户端
send(serverSocket, \
//关闭
closesocket(serverSocket); } }
//关闭
closesocket(aSocket); closesocket(serverSocket);
aDlg->GetDlgItemText(IDC_EDIT_LOG, strText);
strText += \
aDlg->SetDlgItemText(IDC_EDIT_LOG, strText);
//当你使用完Winsock接口后,要调用下面的函数对其占用的资源进行释放 WSACleanup();
return 0; }
3. 总结
1) MFC进行编程的确比较简单, 用的代码比较少, 又容易管理。唯一不好的地方在于很多细节上的东西在资料上不容易查出来, 关联性非常紧密, 象 AfxSocketInit() 函数就是,函数的实现里包含着很多不容易理解的类, 并且记录了非常多的环境信息, 比如创建的线程等等,
这样在主线程调用后子线程没有调用执行 CSocket 的操作就会出错。还有就是有些接口的设计非常离奇, 象 CSocket::Create 的接口就是, 实现上还执行了 CSocket::Bind , 非常不容易被发现。并且MSDN上对 CSocket::Bind 的说明又明显的提示需要显示执行 CSocket::Bind 操作。
2) SDK 编程能理解函数的调用顺序和代码的结构就比较容易,省去了MFC下封装了不知道什么东西的部分,使得代码的流程容易控制。但是从上面的例子来看非常明显的并且不是那么容易理解。不仅仅有很多奇怪的结构(微软的命名一直如此, 无所云云), 并且函数相关太过于紧密, 初学者想一下子熟悉使用并不容易, 对开发者来说代码管理起来非常麻烦。
共分享92篇相关文档