登录后Socket需重新连接

时间:2021-04-17 17:28:16
第一个c++项目中遇到这样的一个问题:
找到了问题的原因但是不知道错误发生在哪?无从修改...

项目的功能是简单的类似QQ的聊天软件。
1:我把服务端的Socket设置为app的成员变量,并且给app定义一个初始化socket的方法。

WSAData wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
InitSocket();



CDialogLogin LoginUI;
if(LoginUI.DoModal() != IDOK)
{
return TRUE;
}
CMy2IMClientDlg dlg;
INT_PTR nResponse = dlg.DoModal();

2:然后就是登录跳转,可是跳转完重新利用app的(Socket)成员变量进行发送数据,客户端就接受不到。这部分源码为

CTime sendMsgTime = CTime::GetCurrentTime();
sendMsgTime.Format("%Y-%m-%d %H:%M:%S");

string strSendMsg;
CString contentMsg;
GetDlgItemText(IDC_EDIT_SEND, contentMsg);
PackJSON( strSendMsg, 10,
              "from", m_SelfMember.m_MemberId.c_str(),
              "to", m_AimMember.m_MemberId.c_str(),
              "content",contentMsg.GetBuffer(),
              "time", sendMsgTime.Format("%Y-%m-%d %H:%M:%S"),
              "id", "dd"
              );
PackData(strSendMsg, 0x0002);
ASSERT(ptrTempApp->m_hClientSocket == NULL);
send(ptrTempApp->m_hClientSocket, strSendMsg.c_str(), sizeof(strSendMsg), NULL );

3:但是我在第二段源码开始前,重新创建socket,然后赋值给ptrTempApp->m_hClientSocket。再利用新的socket发送数据就会成功。
4:为什么会这样?如何解决?socket是app的成员变量,程序没有结束应该不会失效吧?
5:怎么解决这个问题希望大家给些参考,先谢谢谢大家了.

8 个解决方案

#1


1. 这个 server 是作用于转发,C <--> S <-->C 还是直接 S <-->C ??
2. 需给出了代码.但都是些的周边操作,看不出逻辑..
3. send(ptrTempApp->m_hClientSocket, strSendMsg.c_str(),  sizeof(strSendMsg), NULL ); 这个长度有误

#2


引用 1 楼 doox8086 的回复:
1. 这个 server 是作用于转发,C <--> S <-->C 还是直接 S <-->C ??
2. 需给出了代码.但都是些的周边操作,看不出逻辑..
3. send(ptrTempApp->m_hClientSocket, strSendMsg.c_str(), sizeof(strSendMsg), NULL ); 这个长度有误

1:server 是用于转发,C <--> S <-->C的;
2:还需要哪些代码?

#3


最起码得有 accept(sockfd管理) 与 转发部份
也就是你上面代码的 ptrTempApp  从 accept 到 send 这一个过程 

#4


引用 3 楼 doox8086 的回复:
最起码得有 accept(sockfd管理) 与 转发部份
也就是你上面代码的 ptrTempApp 从 accept 到 send 这一个过程

接收端的代码:
1:创造监听线程

void CMy2IMServerDlg::OnBnClickedOk()
{
GetDlgItem(IDOK)->EnableWindow(false);
SetDlgItemText( IDOK,"监听中.....");
CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)funServerListen, this, 0, NULL);
}

2:线程函数

DWORD WINAPI funServerListen(LPARAM ptrDlg)
{
CMy2IMServerDlg * ptrTempDlg = (CMy2IMServerDlg*)ptrDlg;
ptrTempDlg->m_hServerSocket = socket(AF_INET, SOCK_STREAM ,IPPROTO_TCP);

if(  ptrTempDlg->m_hServerSocket == INVALID_SOCKET)
{
MessageBox(ptrTempDlg->m_hWnd, "创建套接字失败.", "信息", NULL );
return FALSE;
}

SOCKADDR_IN serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(6000);
if( SOCKET_ERROR == bind(ptrTempDlg->m_hServerSocket, (sockaddr*)&serverAddr, sizeof(sockaddr) ))
{
MessageBox(ptrTempDlg->m_hWnd, "绑定端口失败.", "信息", NULL );
return FALSE;
}
if( listen(ptrTempDlg->m_hServerSocket,5) == SOCKET_ERROR)
{
MessageBox(ptrTempDlg->m_hWnd, "监听失败", "信息", NULL );
return FALSE;
}

while (true)
{
if( SocketViewer(ptrTempDlg->m_hServerSocket, 0 ) )
{
sockaddr_in clientAddr;
int clientAddrLength = sizeof(sockaddr_in);
//交给线程的节点数据
Item tempItem;
tempItem.m_ptrDlg = ptrTempDlg;
tempItem.m_ListItemSocket = accept( ptrTempDlg->m_hServerSocket, (sockaddr*)&clientAddr, &clientAddrLength );

if( tempItem.m_ListItemSocket == INVALID_SOCKET)
{
MessageBox(ptrTempDlg->m_hWnd, "接受错误.", "提示信息", NULL);
return FALSE;
}
INT_PTR indexInsert = ptrTempDlg->m_ArrayRecvData.Add(tempItem);
tempItem.m_ItemIndex = indexInsert;
//新建一个线程并处理节点的读事件
tempItem.m_ListItemThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)funServerOpera, &(ptrTempDlg->m_ArrayRecvData.GetAt(indexInsert)), CREATE_SUSPENDED, NULL);
ptrTempDlg->m_ArrayRecvData.GetAt(indexInsert).m_ListItemThread = tempItem.m_ListItemThread ;
ResumeThread(ptrTempDlg->m_ArrayRecvData.GetAt(indexInsert).m_ListItemThread);
}
Sleep(500);
}
}


/*利用select函数判断套接字中是否有为可读,或者可写抑或是其他状况
*/
BOOL SocketViewer(SOCKET hSocket, int fdType, int timeOut );
/*对客户端各种请求的数据包进行解析同时做出相应的操作.
*/
DWORD WINAPI funServerOpera(LPARAM ptrItem)
{
Item ptrTempItem = *((Item*)ptrItem);
char strRecvData [1024] = "";
PACKET pacShowData;
if( 0 < recv(ptrTempItem.m_ListItemSocket, strRecvData, 1024, NULL ))
{
UnPackData( strRecvData, pacShowData);
}
switch(pacShowData.m_Opera)
{
case __LOGIN__:
LoginCheck(  ptrTempItem.m_ListItemSocket, pacShowData.m_Data, (LPARAM)ptrTempItem.m_ptrDlg);
break;
case __CHAT__:
MessageBox( ptrTempItem.m_ptrDlg->m_hWnd,"聊天操作","信息提示窗口",NULL);
break;
default:
MessageBox( ptrTempItem.m_ptrDlg->m_hWnd,"非法操作", "信息提示窗口", NULL);
ptrTempItem.m_ptrDlg->m_ArrayRecvData.RemoveAt(ptrTempItem.m_ItemIndex);
break;
}
Sleep(100);
return TRUE;
}

#5


你的接收端是作为服务器端的(就是C/S里面的S)
那么你的发送端,就是顶楼的代码中
你发送之前,有连接服务器端6000端口成功吗?
另外你的ptrTempApp是怎么得到的?

#6


引用 5 楼 king_hhuang 的回复:
你的接收端是作为服务器端的(就是C/S里面的S)
那么你的发送端,就是顶楼的代码中
你发送之前,有连接服务器端6000端口成功吗?
另外你的ptrTempApp是怎么得到的?


CMy2IMClientApp *ptrTempApp = (CMy2IMClientApp *)AfxGetApp();

#7


后面贴的代码也只是 C --[login]> S [LoginCheck] --[login ask]--> C
按你的代码逻辑应该有
CI-- [send msg to c2] -->  [recv] S  [send] -->C2
代码没多少行,自已跟踪下好了,确保相关的变量可用(生命周期, 重点在于 sockefd 管理)....

3楼问 ptrTempApp ..你贴一段不痛不痒的代码
5楼问 ..你又来行CMy2IMClientApp *ptrTempApp = (CMy2IMClientApp *)AfxGetApp(); - -!!!

ptrTempApp-> m_hClientSocket; //<<重点是这个 socketfd
不管你怎么..这个sockfd 它都得是 m_ArrayRecvData.GetAt(客户端xxx).m_ListItemSocket 来的.
然后才有 S send(sockfd,....) 转发操作..

#8


int len = send(ptrTempApp->m_hClientSocket, strSendMsg.c_str(),  strSendMsg.length(), NULL );
看看len是多少,然后WSAGetLastError看看

#1


1. 这个 server 是作用于转发,C <--> S <-->C 还是直接 S <-->C ??
2. 需给出了代码.但都是些的周边操作,看不出逻辑..
3. send(ptrTempApp->m_hClientSocket, strSendMsg.c_str(),  sizeof(strSendMsg), NULL ); 这个长度有误

#2


引用 1 楼 doox8086 的回复:
1. 这个 server 是作用于转发,C <--> S <-->C 还是直接 S <-->C ??
2. 需给出了代码.但都是些的周边操作,看不出逻辑..
3. send(ptrTempApp->m_hClientSocket, strSendMsg.c_str(), sizeof(strSendMsg), NULL ); 这个长度有误

1:server 是用于转发,C <--> S <-->C的;
2:还需要哪些代码?

#3


最起码得有 accept(sockfd管理) 与 转发部份
也就是你上面代码的 ptrTempApp  从 accept 到 send 这一个过程 

#4


引用 3 楼 doox8086 的回复:
最起码得有 accept(sockfd管理) 与 转发部份
也就是你上面代码的 ptrTempApp 从 accept 到 send 这一个过程

接收端的代码:
1:创造监听线程

void CMy2IMServerDlg::OnBnClickedOk()
{
GetDlgItem(IDOK)->EnableWindow(false);
SetDlgItemText( IDOK,"监听中.....");
CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)funServerListen, this, 0, NULL);
}

2:线程函数

DWORD WINAPI funServerListen(LPARAM ptrDlg)
{
CMy2IMServerDlg * ptrTempDlg = (CMy2IMServerDlg*)ptrDlg;
ptrTempDlg->m_hServerSocket = socket(AF_INET, SOCK_STREAM ,IPPROTO_TCP);

if(  ptrTempDlg->m_hServerSocket == INVALID_SOCKET)
{
MessageBox(ptrTempDlg->m_hWnd, "创建套接字失败.", "信息", NULL );
return FALSE;
}

SOCKADDR_IN serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(6000);
if( SOCKET_ERROR == bind(ptrTempDlg->m_hServerSocket, (sockaddr*)&serverAddr, sizeof(sockaddr) ))
{
MessageBox(ptrTempDlg->m_hWnd, "绑定端口失败.", "信息", NULL );
return FALSE;
}
if( listen(ptrTempDlg->m_hServerSocket,5) == SOCKET_ERROR)
{
MessageBox(ptrTempDlg->m_hWnd, "监听失败", "信息", NULL );
return FALSE;
}

while (true)
{
if( SocketViewer(ptrTempDlg->m_hServerSocket, 0 ) )
{
sockaddr_in clientAddr;
int clientAddrLength = sizeof(sockaddr_in);
//交给线程的节点数据
Item tempItem;
tempItem.m_ptrDlg = ptrTempDlg;
tempItem.m_ListItemSocket = accept( ptrTempDlg->m_hServerSocket, (sockaddr*)&clientAddr, &clientAddrLength );

if( tempItem.m_ListItemSocket == INVALID_SOCKET)
{
MessageBox(ptrTempDlg->m_hWnd, "接受错误.", "提示信息", NULL);
return FALSE;
}
INT_PTR indexInsert = ptrTempDlg->m_ArrayRecvData.Add(tempItem);
tempItem.m_ItemIndex = indexInsert;
//新建一个线程并处理节点的读事件
tempItem.m_ListItemThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)funServerOpera, &(ptrTempDlg->m_ArrayRecvData.GetAt(indexInsert)), CREATE_SUSPENDED, NULL);
ptrTempDlg->m_ArrayRecvData.GetAt(indexInsert).m_ListItemThread = tempItem.m_ListItemThread ;
ResumeThread(ptrTempDlg->m_ArrayRecvData.GetAt(indexInsert).m_ListItemThread);
}
Sleep(500);
}
}


/*利用select函数判断套接字中是否有为可读,或者可写抑或是其他状况
*/
BOOL SocketViewer(SOCKET hSocket, int fdType, int timeOut );
/*对客户端各种请求的数据包进行解析同时做出相应的操作.
*/
DWORD WINAPI funServerOpera(LPARAM ptrItem)
{
Item ptrTempItem = *((Item*)ptrItem);
char strRecvData [1024] = "";
PACKET pacShowData;
if( 0 < recv(ptrTempItem.m_ListItemSocket, strRecvData, 1024, NULL ))
{
UnPackData( strRecvData, pacShowData);
}
switch(pacShowData.m_Opera)
{
case __LOGIN__:
LoginCheck(  ptrTempItem.m_ListItemSocket, pacShowData.m_Data, (LPARAM)ptrTempItem.m_ptrDlg);
break;
case __CHAT__:
MessageBox( ptrTempItem.m_ptrDlg->m_hWnd,"聊天操作","信息提示窗口",NULL);
break;
default:
MessageBox( ptrTempItem.m_ptrDlg->m_hWnd,"非法操作", "信息提示窗口", NULL);
ptrTempItem.m_ptrDlg->m_ArrayRecvData.RemoveAt(ptrTempItem.m_ItemIndex);
break;
}
Sleep(100);
return TRUE;
}

#5


你的接收端是作为服务器端的(就是C/S里面的S)
那么你的发送端,就是顶楼的代码中
你发送之前,有连接服务器端6000端口成功吗?
另外你的ptrTempApp是怎么得到的?

#6


引用 5 楼 king_hhuang 的回复:
你的接收端是作为服务器端的(就是C/S里面的S)
那么你的发送端,就是顶楼的代码中
你发送之前,有连接服务器端6000端口成功吗?
另外你的ptrTempApp是怎么得到的?


CMy2IMClientApp *ptrTempApp = (CMy2IMClientApp *)AfxGetApp();

#7


后面贴的代码也只是 C --[login]> S [LoginCheck] --[login ask]--> C
按你的代码逻辑应该有
CI-- [send msg to c2] -->  [recv] S  [send] -->C2
代码没多少行,自已跟踪下好了,确保相关的变量可用(生命周期, 重点在于 sockefd 管理)....

3楼问 ptrTempApp ..你贴一段不痛不痒的代码
5楼问 ..你又来行CMy2IMClientApp *ptrTempApp = (CMy2IMClientApp *)AfxGetApp(); - -!!!

ptrTempApp-> m_hClientSocket; //<<重点是这个 socketfd
不管你怎么..这个sockfd 它都得是 m_ArrayRecvData.GetAt(客户端xxx).m_ListItemSocket 来的.
然后才有 S send(sockfd,....) 转发操作..

#8


int len = send(ptrTempApp->m_hClientSocket, strSendMsg.c_str(),  strSendMsg.length(), NULL );
看看len是多少,然后WSAGetLastError看看