I making a simple check login program with mfc. Im using WSAAsyncselect function to make a non blocking socket. Everytimes theres someone login, the server will send back to all current client a message "user x has login in" and then, they will show that message on their message log.
Usually, i can only update value from a button calling WSAAsyncselect funtion after send the data to server. for example
void CClientDlg::OnBnClickedLogin()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
if ((m_username == "") || (m_password == ""))
{
return;
}
client = socket(AF_INET, SOCK_STREAM, 0);
if (client == INVALID_SOCKET)
{
return;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
char* IPstr = CT2A(IP);
serverAddr.sin_addr.s_addr = inet_addr(IPstr);
int error = connect(client, (sockaddr*)&serverAddr, sizeof(serverAddr));
if (error == SOCKET_ERROR) {
return;
}
modestr = _T("1 ") + m_username + _T(",") + m_password;
SendInfo(modestr);
WSAAsyncSelect(client, m_hWnd, WM_SOCKET, FD_READ | FD_CLOSE);
UpdateData(FALSE);
}
On server, i have this
BEGIN_MESSAGE_MAP(CServerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(WM_SOCKET, SockMsg)
END_MESSAGE_MAP()
LRESULT CServerDlg::SockMsg(WPARAM wParam, LPARAM lParam) {
if (WSAGETSELECTERROR(lParam))
{
closesocket(wParam);
MessageBox(_T("error"));
}
switch (WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
{
//accept client
clientSocks.push_back(CLIENT(accept(wParam, NULL, NULL), "unidentified user"));
break;
}
case FD_READ:
{
//check login codes
//check login codes
//check login codes
for (int i = 0; i < num_clients; i++) {
CString message = _T("0 ") + CString(user.c_str()) + _T("login\r\n");
SendResponse(clientSocks[i].clientSocket, message); //a send funtion to send data to
//another socker
}
}
There's anyway to update data automatically after the server send data to these clients
Not answering your question, because this text would be too long for a comment.
I think you are completely misunderstanding how
WSAAsyncSelectworks. The function does not open a second communication channel from the "client" to the "server" that is based on Windows messages. (There is already a channel: the network connection via sockets.)You use
WSAAsyncSelectto allow that the data transfer happens in the background while the user interface's message loop can keep running and can respond to user activity.The
nMsgargument,WM_SOCKETin your case, is not sent across to a different executable, but is sent to the application itself when the requested event happens. These tell "hey, I've just received data!", "hey, the network connection was closed", "hey, there's now room to write more data".In your example, it does not make sense to request
FD_READevents when the application does not read data.In addition, since both your "client" and your "server" seem to be user interface applications, both should use
WSAASyncSelect. The sending side would listen forFD_WRITE | FD_CLOSEevents (because it has to write data), and the receiving side would listen toFD_READ | FD_CLOSEevents (because it has to read data).Note that, in general, the sending side that uses
WSAAsyncSelectbecomes very complicated to implement: It is not just a simple singlewrite(), because it must be prepared that not all data can be sent at once. Rather, it must keep the data to be sent around, must keep a record of how much has been sent and what has not been sent, yet. Therefore, when the packets are small (a few hundred bytes at most) and infrequent, I would not use asynchronous communication in the sender, and would just hope that networking layer in the OS would be able to cache the data for me and would not block thewrite()call.