日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

MFC下CSocket编程详解

發(fā)布時(shí)間:2024/4/11 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MFC下CSocket编程详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
MFC下CSocket編程詳解:?

1. 常用的函數(shù)和注意事項(xiàng)(詳細(xì)的函數(shù)接口說(shuō)明請(qǐng)查看MSDN):

??? CSocket::Create 初始化(一般寫(xiě)服務(wù)器程序都不要用為好,用下面的 CSocket::Socket 初始化)

?? CSocket::Socket初始化

??? CSocket::SetSockOpt 設(shè)置socket選項(xiàng)

??? CSocket::Bind 綁定地址端口

??? CSocket::Connect 連接

??? CSocket::Listen? 監(jiān)聽(tīng)

??? CSocket::Accept 接收外部連接的socket
?
??? CSocket::Send 發(fā)送內(nèi)容

??? CSocket::Receive 接收內(nèi)容

??? CSocket::Close 關(guān)閉(不等于delete)

??? 1) 在使用MFC編寫(xiě)socket程序時(shí),必須要包含<afxsock.h>都文件。

??? 2) AfxSocketInit() 這個(gè)函數(shù),在使用CSocket前一定要先調(diào)用該函數(shù),否則使用CSocket會(huì)出錯(cuò);并且該函數(shù)還有一個(gè)重要的使用方式,
?????? 就是在某個(gè)線程下使用 CSocket 前一定要調(diào)用,就算主線程調(diào)用了該函數(shù),在子線程下使用 CSocket 也要先調(diào)用該函數(shù),要不會(huì)出錯(cuò)。

??? 3) 還要注意的是, Create 方法已經(jīng)包含了 Bind 方法,如果是以 Create 方法初始化的前提下不能再調(diào)用 Bind ,要不一定出錯(cuò)。

2. 以下是使用例子代碼,通過(guò)例子來(lái)學(xué)習(xí)如何使用 CSocket 進(jìn)行編程, 并且附件上有完整的例子代碼。例子的可以在我的發(fā)布資源中找到:MFC下CSocket編程例子?http://download.csdn.net/source/379597

??? 1) 客戶端主要代碼:

?//初始化
?AfxSocketInit();
??
????????
//創(chuàng)建?CSocket?對(duì)象
?CSocket?aSocket;

?CString?strIP;
?CString?strPort;
?CString?strText;

?
this->GetDlgItem(IDC_EDIT_IP)->GetWindowText(strIP);
?
this->GetDlgItem(IDC_EDIT_PORT)->GetWindowText(strPort);
?
this->GetDlgItem(IDC_EDIT_TEXT)->GetWindowText(strText);

?
//初始化?CSocket?對(duì)象,?因?yàn)榭蛻舳瞬恍枰壎ㄈ魏味丝诤偷刂??所以用默認(rèn)參數(shù)即可
?if(!aSocket.Create())
?
{
??
char?szMsg[1024]?=?{0};

??sprintf(szMsg,?
"create?faild:?%d",?aSocket.GetLastError());

??AfxMessageBox(szMsg);
??
return;
?}


?
//轉(zhuǎn)換需要連接的端口內(nèi)容類型
?int?nPort?=?atoi(strPort);
?
????????
//連接指定的地址和端口
?if(aSocket.Connect(strIP,?nPort))
?
{
??
char?szRecValue[1024]?=?{0};

????????????????
//發(fā)送內(nèi)容給服務(wù)器
??aSocket.Send(strText,?strText.GetLength());
??
??
//接收服務(wù)器發(fā)送回來(lái)的內(nèi)容(該方法會(huì)阻塞,?在此等待有內(nèi)容接收到才繼續(xù)向下執(zhí)行)
??aSocket.Receive((void?*)szRecValue,?1024);

??AfxMessageBox(szRecValue);
?}

?
else
?
{
??
char?szMsg[1024]?=?{0};
??
??sprintf(szMsg,?
"create?faild:?%d",?aSocket.GetLastError());
??
??AfxMessageBox(szMsg);
?}


?
//關(guān)閉
?aSocket.Close();

?

??? 2)服務(wù)器端代碼:

?

unsigned?int?StartServer(LPVOID?lParam)
{ ????????//初始化Winscok
????
if?(!AfxSocketInit())
????
{
????????AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
????????
return?1;
????}


????m_exit?
=?false;

????CServerDlg?
*aDlg?=?(CServerDlg?*)lParam;

????CString?strPort;
????
????aDlg
->GetDlgItemText(IDC_EDIT_PORT,?strPort);
????
????UINT?nPort?
=?atoi(strPort);
????
????
//socket------------------------------------------------
????
????CSocket?aSocket,?serverSocket;
????//最好不要使用aSocket.Create創(chuàng)建,因?yàn)槿菀讜?huì)出現(xiàn)10048錯(cuò)誤
????
if?(!aSocket.Socket())
????
{
????????
char?szError[256]?=?{0};
????????
????????sprintf(szError,?
"Create?Faild:?%d",?GetLastError());
????????
????????AfxMessageBox(szError);
????????
????????
return?1;?
????}


????BOOL?bOptVal?
=?TRUE;
????
int?bOptLen?=?sizeof(BOOL);
?????//設(shè)置Socket的選項(xiàng), 解決10048錯(cuò)誤必須的步驟
????aSocket.SetSockOpt(SO_REUSEADDR,?(void?*)&bOptVal,?bOptLen,?SOL_SOCKET); ?//監(jiān)聽(tīng)
????if(!aSocket.Listen(10))
????{????
????????char?szError[256]?=?{0};
????????
????????sprintf(szError,?"Listen?Faild:?%d",?GetLastError());
????????
????????AfxMessageBox(szError);
????????
????????return?1;
????}

????
????CString?strText;
????
????aDlg->GetDlgItemText(IDC_EDIT_LOG,?strText);
????
????strText?+=?"Server?Start!??";
????
????aDlg->SetDlgItemText(IDC_EDIT_LOG,?strText);

????while(!m_exit)
????{
????????//接收外部連接
????????if(!aSocket.Accept(serverSocket))
????????{
????????????continue;
????????}

????????else
????????{
????????????char?szRecvMsg[256]?=?{0};
????????????char?szOutMsg[256]?=?{0};????
????????????
//接收客戶端內(nèi)容:阻塞
????????????serverSocket.Receive(szRecvMsg,?256);

????????????sprintf(szOutMsg,?"Receive?Msg:?%s??",?szRecvMsg);
????????????
????????????aDlg->GetDlgItemText(IDC_EDIT_LOG,?strText);
????????????
????????????strText?+=?szOutMsg;
????????????
????????????aDlg->SetDlgItemText(IDC_EDIT_LOG,?strText);
????? //發(fā)送內(nèi)容給客戶端
????????????serverSocket.Send("Have?Receive?The?Msg",?50);
//關(guān)閉
????????????serverSocket.Close();
????????}
????????
????}
???? //關(guān)閉
????aSocket.Close();
????serverSocket.Close();
????
????aDlg->GetDlgItemText(IDC_EDIT_LOG,?strText);
????
????strText?+=?"Have?Close!";
????
????aDlg->SetDlgItemText(IDC_EDIT_LOG,?strText);

????return?0;
}
????
????//綁定端口
????
if?(!aSocket.Bind(nPort))
????
{
????????
char?szError[256]?=?{0};
????????????
????????sprintf(szError,?
"Bind?Faild:?%d",?GetLastError());
????????????
????????AfxMessageBox(szError);
????????????
????????
return?1;?
????}

??

?

?? 3) SDK 下的服務(wù)器端代碼

?

???????//子線程函數(shù)
???????unsigned?int?StartServer(LPVOID?lParam)
???????
{
????????
???????
//初始化Winsock,?AfxSocketInit()?也是封裝了這些語(yǔ)句,?不過(guò)?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------------------------------------------------
???????????
???????????
//接口對(duì)象
???????????SOCKET?aSocket,?serverSocket;

???????????
//尋址相關(guān)結(jié)構(gòu)
????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,?
"Create?Faild:?%d",?GetLastError());
??
??AfxMessageBox(szError);
??
??
return?1;?
????}


????
//注意,該處非常重要,取值的正確與否決定關(guān)閉scoket后端口是否能正常釋放
????BOOL?bOptVal?=?TRUE;
????
int?bOptLen?=?sizeof(BOOL);
???????????
????????????
//設(shè)置?socket?選項(xiàng),?SOL_SOCKET?和?SO_REUSEADDR?一起使用,?并且后面的參數(shù)如上,?
??????????????關(guān)閉scoket后端口便能正常釋放
?????setsockopt(aSocket,?SOL_SOCKET,?SO_REUSEADDR,?(
char?*)&bOptVal,?bOptLen);?
?
???????????
//尋址相關(guān)結(jié)構(gòu)
????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);
?
???????????
//綁定:?注意參數(shù)的類型轉(zhuǎn)換
????if(bind(aSocket,(sockaddr?*)&aSockaddr,?sizeof(aSockaddr))?==?SOCKET_ERROR)
????
{
??
char?szError[256]?=?{0};
??
??sprintf(szError,?
"Bind?Faild:?%d",?GetLastError());
??
??AfxMessageBox(szError);
??
??
return?1;?
????}


?
????
//監(jiān)聽(tīng)
????if(listen(aSocket,?10)?==?SOCKET_ERROR)
????
{?
??
char?szError[256]?=?{0};
??
??sprintf(szError,?
"Listen?Faild:?%d",?GetLastError());
??
??AfxMessageBox(szError);
??
??
return?1;
????}

?
????CString?strText;

????aDlg
->GetDlgItemText(IDC_EDIT_LOG,?strText);

????strText?
+=?"Server?Start!??";

????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};?
???
???
//接收客戶端內(nèi)容:?阻塞
???recv(serverSocket,?szRecvMsg,?256,?0);

???sprintf(szOutMsg,?
"Receive?Msg:?%s??",?szRecvMsg);
???
???aDlg
->GetDlgItemText(IDC_EDIT_LOG,?strText);
???
???strText?
+=?szOutMsg;

???aDlg
->SetDlgItemText(IDC_EDIT_LOG,?strText);

????????????????????????
//發(fā)送內(nèi)容給客戶端
???send(serverSocket,?"Have?Receive?The?Msg",?50,?0);

????????????????????????
//關(guān)閉
???closesocket(serverSocket);
??}

??
????}

?
????
//關(guān)閉
????closesocket(aSocket);
????closesocket(serverSocket);

????aDlg
->GetDlgItemText(IDC_EDIT_LOG,?strText);
?
????strText?
+=?"Have?Close!";

????aDlg
->SetDlgItemText(IDC_EDIT_LOG,?strText);

???????????
//當(dāng)你使用完Winsock接口后,要調(diào)用下面的函數(shù)對(duì)其占用的資源進(jìn)行釋放
????WSACleanup();

????
return?0;
???????}

3. 總結(jié)
?? 1) MFC進(jìn)行編程的確比較簡(jiǎn)單, 用的代碼比較少, 又容易管理。唯一不好的地方在于很多細(xì)節(jié)上的東西在資料上不容易查出來(lái), 關(guān)聯(lián)性非常緊密, 象 AfxSocketInit() 函數(shù)就是,函數(shù)的實(shí)現(xiàn)里包含著很多不容易理解的類, 并且記錄了非常多的環(huán)境信息, 比如創(chuàng)建的線程等等, 這樣在主線程調(diào)用后子線程沒(méi)有調(diào)用執(zhí)行 CSocket 的操作就會(huì)出錯(cuò)。還有就是有些接口的設(shè)計(jì)非常離奇, 象 CSocket::Create 的接口就是, 實(shí)現(xiàn)上還執(zhí)行了 CSocket::Bind , 非常不容易被發(fā)現(xiàn)。并且MSDN上對(duì) CSocket::Bind 的說(shuō)明又明顯的提示需要顯示執(zhí)行 CSocket::Bind 操作。

?? 2) SDK 編程能理解函數(shù)的調(diào)用順序和代碼的結(jié)構(gòu)就比較容易,省去了MFC下封裝了不知道什么東西的部分,使得代碼的流程容易控制。但是從上面的例子來(lái)看非常明顯的并且不是那么容易理解。不僅僅有很多奇怪的結(jié)構(gòu)(微軟的命名一直如此, 無(wú)所云云), 并且函數(shù)相關(guān)太過(guò)于緊密, 初學(xué)者想一下子熟悉使用并不容易, 對(duì)開(kāi)發(fā)者來(lái)說(shuō)代碼管理起來(lái)非常麻煩。

總結(jié)

以上是生活随笔為你收集整理的MFC下CSocket编程详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。