I have set up a Winsock2 connection but I need to cover the case where internet is down. Here is my code;
#include <winsock2.h>
#include <windows.h>
#include <ctime>
int main()
{
WSADATA w;
if(WSAStartup(MAKEWORD(2,2),&w)) return 0;
sockaddr_in sad;
sad.sin_family=AF_INET;
sad.sin_addr.s_addr=inet_addr("200.20.186.76");
sad.sin_port=htons(123);
sockaddr saddr;
int saddr_l=sizeof(saddr);
int s=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(s==INVALID_SOCKET) return 0;
char msg[48]={8};
if(sendto(s,msg,sizeof(msg),0,(sockaddr*)&sad,sizeof(sad))==SOCKET_ERROR) return 0;
if(recvfrom(s,msg,48,0,&saddr,&saddr_l)==SOCKET_ERROR) return 0;
if(closesocket(s)==SOCKET_ERROR) return 0;
if(WSACleanup()) return 0;
return 0;
}
Here it waits for the call to return as it's documented. I have two questions.
Can I set a timeout like we can do when using select
How else can I prevent the waiting and make it return immediately? Documentation states that:
When issuing a blocking Winsock call such as sendto, Winsock may need to wait for a network event before the call can complete. Winsock performs an alertable wait in this situation, which can be interrupted by an asynchronous procedure call (APC) scheduled on the same thread.
How to do that?
If you want to issue a recvfrom() and have it return immediately, then decide on your own how long to wait (I'm assuming Windows since you included winsock2.h), you can make an asynchronous OVERLAPPED request, then wait for the completion at any time by waiting for the hEvent member of the OVERLAPPED struct to be signaled.
Here's an updated sample based off your original code.
you set the timeout by waiting as long as you need with WaitForSingleObject (below I wait for 10 seconds 6 times)
by passing an OVERLAPPED pointer, you are indicating that you will wait for the completion yourself. Note that the OVERLAPPED struct cannot go out of scope until the hEvent is signaled. (or freed, if the OVERLAPPED was dynamically allocated).
Letting the OVERLAPPED go out of scope before guaranteeing the IO completed is a common Winsock bug (I've been working on Winsock for over 10 years or so - I've seen many variations of this bug)
As commented below, if you don't know hEvent has been signaled, then after calling closesocket you must wait for hEvent to be signaled before continuing - closesocket does not guarantee all asynchronous IO request have completed before returning.
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include <ctime>
int main()
{
WSADATA w;
if (WSAStartup(MAKEWORD(2, 2), &w)) return 0;
sockaddr_in sad;
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr("200.20.186.76");
sad.sin_port = htons(123);
sockaddr saddr;
int saddr_l = sizeof(saddr);
int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) return 0;
char msg[48] = { 8 };
if (sendto(s, msg, sizeof(msg), 0, (sockaddr*)&sad, sizeof(sad)) == SOCKET_ERROR) return 0;
OVERLAPPED ov{};
ov.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
if (ov.hEvent == nullptr) return 0;
WSABUF wsabuffer{};
wsabuffer.buf = msg;
wsabuffer.len = 48;
DWORD flags = 0;
if (WSARecvFrom(s, &wsabuffer, 1, nullptr, &flags, &saddr, &saddr_l, &ov, nullptr) == SOCKET_ERROR)
{
DWORD gle = WSAGetLastError();
if (gle != WSA_IO_PENDING) return 0;
}
for (DWORD recv_count = 0; recv_count < 6; ++recv_count)
{
DWORD wait = WaitForSingleObject(ov.hEvent, 10000);
if (wait == WAIT_FAILED) return 0;
if (wait == WAIT_OBJECT_0) break; // WSARecvFrom completed
if (wait == WAIT_TIMEOUT) continue; // WSARecvFrom is still pended waiting for data
}
// assuming WSARecvFrom completed - i.e. ov.hEvent was signaled
DWORD transferred;
if (WSAGetOverlappedResult(s, &ov, &transferred, FALSE, &flags))
{
// WSARecvFrom completed successfully - 'transferred' shows the # of bytes that were received
}
else
{
DWORD gle = WSAGetLastError();
gle;
// WSARecvFrom failed with the error code in 'gle'
}
if (closesocket(s) == SOCKET_ERROR) return 0;
// with real code, we must guarantee that hEvent is set after calling closesocket
// e.g. if we get here in an error path
// closesocket() won't guarantee all async IO has completed before returning
WaitForSingleObject(ov.hEvent, INFINITE);
if (WSACleanup()) return 0;
return 0;
}
Related
Why does string a return 'C' instead of "C:\Users\Desktop\Project phoneedge\ForMark\Top"?
When I tested it in a empty c++ project, and before I moved some of my code from ThreadFunction to StartButton it worked(The UI is suppose to update constantly but the socket recv() is cockblocking it causing it only update once so I moved the UI code to startbutton)
This is the server code, after start button is pressed, initiate the socket and there is a thread created to run the listen() accept() and recv(). The close button closes the socket and the thread.
Server Code(MFC project)
void CUIServerDlg::StartButton()
{
WSADATA Winsockdata;
int iTCPClientAdd = sizeof(TCPClientAdd);
WSAStartup(MAKEWORD(2, 2), &Winsockdata);
TCPServerAdd.sin_family = AF_INET;
TCPServerAdd.sin_addr.s_addr = inet_addr("127.0.0.1");
TCPServerAdd.sin_port = htons(8000);
TCPServersocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(TCPServersocket, (SOCKADDR*)&TCPServerAdd, sizeof(TCPServerAdd));
bRunning = true;
hthread = CreateThread(NULL, 0, ThreadFunction, this, 0, &ThreadID);
WaitForSingleObject(hthread, INFINITE);
funRunning = true;
while (funRunning == true) {
vector<string> caseOne;
/*string a;
char RecvBuffer[512];//this is the declaration in member class
int iRecvBuffer = strlen(RecvBuffer) + 1;*/
**a = RecvBuffer;**//a is a String, RecvBuffer is a path name like c:\user..
//Find files,This part of code is left out because it should not effect the question
//put the files found in a vector, then display it on a listbox
for (string fileVec : caseOne) {
CString fileunderPath;
string filevector1 = fileVec;
fileunderPath = filevector1.c_str();//conversion for AddString
list1.AddString(fileunderPath);
}
Sleep(1000);//The code updates every 1 second , when file names are modified is displays immediately.
}
}
I am suppose to change Sleep(1000) into WaitForSingleObject() to replace WM_Timer for the assignment but I don't know how since you need a handle, do I create another thread?
void CUIServerDlg::CloseButton()
{
bRunning = false;
funRunning = false;
WaitForSingleObject(hthread, INFINITE);
CloseHandle(hthread);
closesocket(TCPServersocket);
}
So I have never learned anything about socket and thread prior to this project, the idea of the code below is to use a thread to run a while loop to constantly check for new cilents to send things in, do make sure to correct me if the thought process is wrong.
DWORD WINAPI CUIServerDlg::ThreadFunction(LPVOID lpParam) {
CUIServerDlg* This = (CUIServerDlg*)lpParam;
while (This->bRunning == true) {
int iListen = listen(This->TCPServersocket, 10);
if (iListen == INVALID_SOCKET)
OutputDebugString(_T("FAIL LISTEN\n"));
This->sAccecpSocket = accept(This->TCPServersocket, (SOCKADDR*)&This->iTCPClientAdd, &This->iTCPClientAdd);
recv(This->sAccecpSocket, This->RecvBuffer, This->iRecvBuffer, 0);
}
return 0;
}
Client Code (Empty c++ project)
int main(){
string a = "C:\\Users\\Desktop\\Project phoneedge\\ForMark\\Top";
const char* SenderBuffer = a.c_str();
int iSenderBuffer = strlen(SenderBuffer) + 1;
WSAStartup(MAKEWORD(2, 2), &WinSockData);
TCPClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
TCPServerAdd.sin_family = AF_INET;
TCPServerAdd.sin_addr.s_addr = inet_addr("127.0.0.1");
TCPServerAdd.sin_port = htons(8000);
connect(TCPClientSocket,(SOCKADDR*)&TCPServerAdd,sizeof(TCPServerAdd));
send(TCPClientSocket, SenderBuffer, iSenderBuffer, 0);
closesocket(TCPClientSocket);
WSACleanup();
system("PAUSE");
return 0;
}
The TCP protocol passes the data by byte stream.
It means the client passes the data byte by byte rather than pass all the data at one time.
When you receive the data from the client. The passing procedure maybe not be finished.
So you need to check whether the data is finished passing after receiving some data by one recv call and then save the sub-data until receiving all the data.
I have a thread that is receiving data on the socket. I am using WSAWaitForMultipleEvents() since I have another custom event that is used to wake up the thread at the end of the program.
Here is how the socket is setup with the first event in the event array:
int ret = 0;
u_long iMode = 0;
ret = ioctlsocket(sock, FIONBIO, &iMode);
if (ret != NO_ERROR)
return some_enum_error;
else if (WSAEventSelect(sock, events[0], FD_READ) != 0)
return some_enum_error;
Now, we go to wait for the event:
bool result = false;
DWORD ret;
WSANETWORKEVENTS NetworkEvents;
ret = WSAWaitForMultipleEvents(2, events, FALSE, WSA_INFINITE, FALSE);
if (ret == WAIT_OBJECT_0 + 0) {
WSAEnumNetworkEvents(sock, events[0], &NetworkEvents);
result = true;
}
and now, read the data with:
recv(sock, (char*)buf, static_cast<size_t>(len), flags)
This works, most of the time. However, if the network has a big latency, I am seeing issues where the event fires but there is no data available from the recv() function. Once I hit this issue, I added the code to go back and recv() again after some time, and the data is there just fine.
Any ideas why this happens? How can I make this work without the additional poll?
Trying to write a client which will try to receive data till 3 seconds. I have implemented the connect method using select by below code.
//socket creation
m_hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
m_stAddress.sin_family = AF_INET;
m_stAddress.sin_addr.S_un.S_addr = inet_addr(pchIP);
m_stAddress.sin_port = htons(iPort);
m_stTimeout.tv_sec = SOCK_TIMEOUT_SECONDS;
m_stTimeout.tv_usec = 0;
//connecting to server
long iMode = 1;
int iResult = ioctlsocket(m_hSocket, FIONBIO, &iMode);
connect(m_hSocket, (struct sockaddr *)&m_stAddress, sizeof(m_stAddress));
long iMode = 0;
iResult = ioctlsocket(m_hSocket, FIONBIO, &iMode);
fd_set stWrite;
FD_ZERO(&stWrite);
FD_SET(m_hSocket, &stWrite);
iResult = select(0, NULL, &stWrite, NULL, &m_stTimeout);
if((iResult > 0) && (FD_ISSET(m_hSocket, &stWrite)))
return true;
But I cannot figure out what I am missing at receiving timeout with below code? It doesn't wait if the server connection got disconnected. It just returns instantly from select method.
Also how can I write a non blocking socket call with timeout for socket send.
long iMode = 1;
int iResult = ioctlsocket(m_hSocket, FIONBIO, &iMode);
fd_set stRead;
FD_ZERO(&stRead);
FD_SET(m_hSocket, &stRead);
int iRet = select(0, &stRead, NULL, NULL, &m_stTimeout);
if ((iRet > 0) && (FD_ISSET(m_hSocket, &stRead)))
{
while ((iBuffLen-1) > 0)
{
int iRcvLen = recv(m_hSocket, pchBuff, iBuffLen-1, 0);
if (iRcvLen == SOCKET_ERROR)
{
return false;
}
else if (iRcvLen == 0)
{
break;
}
pchBuff += iRcvLen;
iBuffLen -= iRcvLen;
}
}
The first parameter to select should not be 0.
Correct usage of select can be found here :
http://developerweb.net/viewtopic.php?id=2933
the first parameter should be the max value of your socket +1 and take interrupted system calls into account if it is non blocking:
/* Call select() */
do {
FD_ZERO(&readset);
FD_SET(socket_fd, &readset);
result = select(socket_fd + 1, &readset, NULL, NULL, NULL);
} while (result == -1 && errno == EINTR);
This is just example code you probably need the timeout parameter as well.
If you can get EINTR this will complicate your required logic, because if you get EINTR you have to do the same call again, but with the remaining time to wait for.
I think for non blocking mode one needs to check the recv() failure along with a timeout value. That mean first select() will return whether the socket is ready to receive data or not. If yes it will go forward else it will sleep until timeout elapses on the select() method call line. But if the receive fails due to some uncertain situations while inside read loop there we need to manually check for socket error and maximum timeout value. If the socket error continues and timeout elapses we need to break it.
I'm done with my receive timeout logic with non blocking mode.
Please correct me if I am wrong.
bool bReturn = true;
SetNonBlockingMode(true);
//check whether the socket is ready to receive
fd_set stRead;
FD_ZERO(&stRead);
FD_SET(m_hSocket, &stRead);
int iRet = select(0, &stRead, NULL, NULL, &m_stTimeout);
DWORD dwStartTime = GetTickCount();
DWORD dwCurrentTime = 0;
//if socket is not ready this line will be hit after 3 sec timeout and go to the end
//if it is ready control will go inside the read loop and reads data until data ends or
//socket error is getting triggered continuously for more than 3 secs.
if ((iRet > 0) && (FD_ISSET(m_hSocket, &stRead)))
{
while ((iBuffLen-1) > 0)
{
int iRcvLen = recv(m_hSocket, pchBuff, iBuffLen-1, 0);
dwCurrentTime = GetTickCount();
if ((iRcvLen == SOCKET_ERROR) && ((dwCurrentTime - dwStartTime) >= SOCK_TIMEOUT_SECONDS * 1000))
{
bReturn = false;
break;
}
else if (iRcvLen == 0)
{
break;
}
pchBuff += iRcvLen;
iBuffLen -= iRcvLen;
}
}
SetNonBlockingMode(false);
return bReturn;
I am trying to implement a server in C++/Linux that regularly takes user input from the terminal. Initially I had implemented two separate threads to handle this behavior. But I realized that I would need something like pthread_cancel to cancel the server thread in case the user wanted to shut down the server.
I then decided that it might be better to handle both actions in the same thread, so I dont have to worry about resource leakage. So what I have now is a 'select' call that selects over the stdin fd as well as my accepting fd. My code looks something like this...
fdset readfds;
FD_SET(acceptfd, &readfds);
FD_SET(stdinfd, &readfds);
while(1) {
select(n, &readfds, NULL, NULL, NULL);
....
}
For some reason I am no longer able to read input from stdin. This works fine when I remove either one of the two fds from my fd set, the other ome performs as expected. But when I leave them both in, while the acceptfd still accepts incoming connections, the stdinfd fails to respond to terminal input.
Does anyone know what I might be doing wrong here? Is this approach inherently flawed? Should I be focusing on keeping the two actions as separate threads and figuring out a way to exit cleanly instead?
Thanks for reading!!
As Ambroz commented, multiplexing stdin and some listened fd is possible.
But select is an old, nearly obsolete syscall, you should prefer using poll(2). If you insist on still using select(2) syscall, you should clear the readfds at first with FD_ZERO inside the loop. And the FD_SET macros should be inside the while loop, because select is permitted to modify the readfds.
The poll syscall is preferable to select because select impose a wired-in limit to the number of file descriptors the process can have (typically 1024, while the kernel is today able to deal with a bigger number of fds, eg 65536). In other words, select requires that every fd is < 1024 (which is false today). poll is able to deal with any set of any fd. The first argument to poll is an array (which you could calloc if you wanted to) whose size is the number of fds you want to multiplex. In your case, it is two (stdin and the second listened fd), so you can make it a local variable. Be sure to clear and initialize it before every call to poll.
You could debug with a debugger like gdb or just use strace
This epoll code works for me:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 4711
int main(void) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htons(INADDR_ANY);
bind(sockfd, (struct sockaddr*) &addr, sizeof (addr));
listen(sockfd, 10);
int epollfd = epoll_create1(0);
struct epoll_event event;
// add stdin
event.events = EPOLLIN|EPOLLPRI|EPOLLERR;
event.data.fd = STDIN_FILENO;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &event) != 0) {
perror("epoll_ctr add stdin failed.");
return 1;
}
// add socket
event.events = EPOLLIN|EPOLLPRI|EPOLLERR;
event.data.fd = sockfd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event) != 0) {
perror("epoll_ctr add sockfd failed.");
return 1;
}
char *line = NULL;
size_t linelen = 0;
for (;;) {
int fds = epoll_wait(epollfd, &event, 1, -1);
if (fds < 0) {
perror("epoll_wait failed.");
return 2;
}
if (fds == 0) {
continue;
}
if (event.data.fd == STDIN_FILENO) {
// read input line
int read = getline(&line, &linelen, stdin);
if (read < 0) {
perror("could not getline");
return 3;
}
printf("Read: %.*s", read, line);
} else if (event.data.fd == sockfd) {
// accept client
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof (client_addr);
int clientfd = accept(sockfd, (struct sockaddr*) &client_addr, &addrlen);
if (clientfd == -1) {
perror("could not accept");
return 4;
}
send(clientfd, "Bye", 3, 0);
close(clientfd);
} else {
// cannot happen™
fprintf(stderr, "Bad fd: %d\n", event.data.fd);
return 5;
}
}
close(epollfd);
close(sockfd);
return 0;
}
I have a chat application that has a separate thread to listen for incoming messages.
while (main thread not calling for receiver to quit) {
string message = tcpCon.tcpReceive(); // Relies on the recv() function
processIncomingMessage(message);
}
This way of working has one big problem. Most of the time, the loop will be blocking on recv() so the receiver thread won't quit. What would be a proper way to tackle this issue without forcing thread termination after a couple of seconds?
Close the socket with shutdown() to close it for all receivers.
This prints out 'recv returned 0' on my system, indicating that the receiver saw an orderly shutdown. Comment out shutdown() and watch it hang forever.
Longer term, OP should fix the design, either using select or including an explicit quit message in the protocol.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
/* Free on my system. YMMV */
int port = 7777;
int cd;
void *f(void *arg)
{
/* Hack: proper code would synchronize here */
sleep(1);
/* This works: */
shutdown(cd, SHUT_RDWR);
close(cd);
return 0;
}
int main(void)
{
/* Create a fake server which sends nothing */
int sd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sa = { 0 };
const int on = 1;
char buf;
pthread_t thread;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(port);
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
/* Other error reporting omitted for clarity */
if (bind(sd, (const struct sockaddr*)&sa, sizeof sa) < 0) {
perror("bind");
return EXIT_FAILURE;
}
/* Create a client */
listen(sd, 1);
cd = socket(AF_INET, SOCK_STREAM, 0);
connect(cd, (const struct sockaddr*)&sa, sizeof sa);
accept(sd, 0, 0);
/* Try to close socket on another thread */
pthread_create(&thread, 0, f, 0);
printf("recv returned %d\n", recv(cd, &buf, 1, 0));
pthread_join(thread, 0);
return 0;
}
You could use select() to wait for incoming data and avoid blocking in recv(). select() will also block, but you can have it time out after a set interval so that the while loop can continue and check for signals to quit from the main thread:
while (main thread not calling for receiver to quit) {
if (tcpCon.hasData(500)) { // Relies on select() to determine that data is
// available; times out after 500 milliseconds
string message = tcpCon.tcpReceive(); // Relies on the recv() function
processIncomingMessage(message);
}
}
If you close the socket in another thread, then recv() will exit.
calling close on the socket from any other thread will make the recv call fail instantly.