我想寫一個 TCP 一對多通信的程式,就是服務器端利用多執行緒技術(不使用Select等任何模型), 服務器端能將訊息群發給所有已連接的客戶端, 我參考了其他一些程式,發現基本思路 是將每個執行緒中 accept函式回傳的套接字 都保存到一個套接字陣列中,套接字地址也保存到一個陣列中。然后在“群發”的 按鈕訊息中,用for回圈 遍歷套接字陣列,回圈執行 send函式將訊息發送給套接字陣列中所有的套接字。 可我用send()函式發送就產生SOCKET_ERROR錯誤,輸出錯誤代碼是10038,無效的套接字,說明套接字根本沒保存到套接字陣列中去,用list結構保存套接字也是這樣,不行,請問這是為什么,我的關鍵代碼如下:。
BOOL CListWinDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
WSADATA wsaData;
WORD sockVersion=MAKEWORD(2,2);
sockSer=socket(AF_INET,SOCK_STREAM,0);
addrSer.sin_family=AF_INET;
addrSer.sin_port=htons(5566);
addrSer.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
int len =sizeof(SOCKADDR);
bind(sockSer,(SOCKADDR*) &addrSer,len);
listen(sockSer,5);
RECVPARAM *pRecvParam=new RECVPARAM;
pRecvParam->sock=sockSer;
pRecvParam->hwnd=m_hWnd;
HANDLE hThread=CreateThread(NULL,0,WaitProc,(LPVOID)pRecvParam,0,NULL);
CloseHandle(hThread);
return 0;
}
DWORD WINAPI CListWinDlg::WaitProc(LPVOID lpParameter) //接受連接執行緒
{
CListWinDlg *pServer=new CListWinDlg;
SOCKET sock=((RECVPARAM*)lpParameter)->sock;
HWND hwnd=((RECVPARAM*)lpParameter)->hwnd;
SOCKET sockConn;
SOCKADDR_IN addrCli;
int len =sizeof(SOCKADDR);
int num=0;
while(1)
{
Sleep(10); //這句有什么用?
sockConn=accept(sock,(SOCKADDR*) &addrCli,&len);
if(INVALID_SOCKET == sockConn)
{
CString strNotice = "accept()失敗,再次嘗試 ...... ";
::AfxMessageBox(strNotice);
continue;
}
else{ AfxMessageBox("一個客戶端已成功連接");
// pServer->m_listConn.push_back(addrCli);
// pServer->m_sockConn.push_back(sockConn);
pServer->m_Clients[num]=sockConn; //將套接字保存到陣列中,
pServer->addrFrom[num]=addrCli;
num++;
} //將套接字地址保存到陣列中
// int num2=sizeof(pServer->m_Clients)/sizeof(pServer->m_Clients[0]);
}
return TRUE;
}
void CListWinDlg::OnSend()
{
char buff[200];
char * ct;
CTime time = CTime::GetCurrentTime(); //獲取當前時間
CString t = time.Format(" %H:%M:%S"); //設定時間顯示格式
ct=(char*)t.GetBuffer(0); //cstring 轉 char*
c_sendbuf.GetWindowText(buff,200);
c_sendbuf.SetWindowText(NULL);
CString Ser="服務器: >";
strcat(buff,ct);
int iSendFalseCount=0;
CListWinDlg *pServer=new CListWinDlg;
// for (sockiterator = m_sockConn.begin(); sockiterator != m_sockConn.end(); ++sockiterator)
// for (list<SOCKET>::iterator itr=pServer->m_sockConn.begin();itr!=pServer->m_sockConn.end();itr++)
for(int i=0;i<3;i++)
{
int vetcal=send(pServer->m_Clients[i],buff,strlen(buff)+1,0);
if (vetcal==SOCKET_ERROR)
iSendFalseCount++;
}
iSendFalseCount=WSAGetLastError();
char strtemp[5];
itoa(iSendFalseCount, strtemp, 10);
AfxMessageBox(strtemp);
}
頭檔案中定義的陣列如下:
struct RECVPARAM
{
SOCKET sock;
HWND hwnd;
};
class CListWinDlg : public CDialog
{
// Construction
public:
CListWinDlg(CWnd* pParent = NULL); // standard constructor
SOCKET sockSer,sockConn;
SOCKET m_Clients[10]; //保存套接字的陣列
SOCKADDR_IN addrFrom[10];
list<SOCKET> m_sockConn;
list<SOCKADDR_IN> m_listConn;
list<SOCKET>::iterator sockiterator;
SOCKADDR_IN addrSer;
list<string> test;
list<string>::iterator testiterator;
static DWORD WINAPI WaitProc(LPVOID lpParameter);
static DWORD WINAPI RecvProc(LPVOID lpParameter);
uj5u.com熱心網友回復:
有客戶端連接到么? send時的SOCKET引數是多少? TRACE 日志或設定斷點查看uj5u.com熱心網友回復:
你在保存和使用的時候分別CListWinDlg *pServer=new CListWinDlg;
所以你保存和使用的不是同一個物件實體,這兩個物件的資料是不共享的
你應該使用同一個,或者使用靜態陣列
uj5u.com熱心網友回復:
客戶端能連接成功,服務器都能接收任何客戶端發送的訊息,只是服務器不能向客戶端發送訊息,send時的SOCKET引數是多少? TRACE 日志或設定斷點查看 這些我不知道怎么做
uj5u.com熱心網友回復:
CListWinDlg *pServer=new CListWinDlg;是一個 與 原 對話框 無關的 新物件 !
WaitProc(LPVOID lpParameter)// 傳 對話框 視窗
對話框 定義
RECVPARAM RecvParam;
或者
RECVPARAM *pRecvParam=new RECVPARAM;
放 類外
uj5u.com熱心網友回復:
你客戶端有等待接收訊息嗎?如果沒有那就不行。uj5u.com熱心網友回復:
知道問題所在了,把保存套接字的陣列定義在 chatDlg.cpp中就可以了,原來是定義在chatDlg.h中就不行,聽說是為解決連接時重復定義的問題,可為什么放在*dlg.cpp檔案中就解決了重復定義的問題呢?還是不明白。//*******本來在chatDlg.h中定義的,現在移到這里,為解決連接時重復定義問題
SOCKET * m_Clients[10]; //保存套接字的陣列
SOCKADDR_IN addrCli[10];
int num;
//****************************************************
uj5u.com熱心網友回復:
這是已經寫好的程式,完全可正常運行。https://download.csdn.net/download/wuxia2118/10946379
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/55924.html
標籤:網絡編程
