I have 2 questions:
first - I try to connect one client to server each time. (the accept function is in thread) but the connection fail in accept - return always -1 (instead of zero).
the second question - how I can add timeout for to accepting client?
server.h
class Server{
public:
void open(int port, object&);
void startThreadOPeration();
void stop(){};
~Server();
private:
sockaddr_in address;
int socketfd;
Object* obj;
void startThread();
std::thread acceptClient;
};
server.cpp
void Server::open(int port,Object& obj) {
this->obj = &obj;
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
if (socketfd == -1) {
throw "Could not create a socket";
}
this->socketfd = socketfd;
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
this->address = address;
if (bind(socketfd, (struct sockaddr *) &this->address, sizeof(this->address)) == -1) {
throw "Could not bind the socket to an IP";
}
if (listen(this->socketfd, 5) == -1) {
throw "Error during listening command";
} else {
std::cout<<"Server is now listening ..."<<std::endl;
}
startThread();
}
void Server::startThreadOPeration() {
while (!side_server::stop) {
// accepting a client
int client_socket = accept(this->socketfd, (struct sockaddr *) &this->address,
(socklen_t *) &this->address); // Return -1
if (client_socket == -1) {
throw "Error accepting client";
}
//do operation
}
void Server::startThread() {
acceptClient = std::thread(&Server::startThreadOPeration,this);
}
Server::~Server(){
close(this->socketfd);
if(acceptClient.joinable()){
this->acceptClient.join();
}
}
thank you for help!
accept() takes 3 parameters - a socket, a pointer to a socket address structure, and a pointer to a socklen_t containing the maximum length of the given socket address structure. On success, the socklen_t will be updated with the actual length of the socket structure.
Unfortunately, your code calls accept() with the address of the this->address variable in the 3rd parameter rather than the address of a valid socklen_t variable. Odds are good this causes this->address to contain what will appear to be complete nonsense when accept() updates what it thinks is a socklen_t but really isn't.
void Server::startThreadOPeration() {
while (!side_server::stop) {
// accepting a client
socklen_t len = sizeof(this->address); // max size of address structure
int client_socket = accept(this->socketfd,
(struct sockaddr *) &this->address,
&tlen); // supply valid max length
if (client_socket == -1) {
throw "Error accepting client";
}
//do operation
}
accept() doesn't do timeouts easily, but select() does:
void Server::startThreadOPeration() {
while (!side_server::stop) {
fd_set readfds;
struct timeval tv;
int result;
FD_ZERO(&readfds);
tv.tv_sec = timeout_s; // number of seconds to wait here
tv.tv_usec = timeout_us; // number of additional us to wait here
FD_SET(this->socketfd, &readfds);
result = select(this->socketfd + 1, &readfds, NULL, NULL, &tv);
if (result > 0)
{
// cheating a bit here since the only thing in readfds will be this->socketfd
// normally you should check what of many file descriptors is set.
socklen_t len = sizeof(this->address);
int client_socket = accept(this->socketfd,
(struct sockaddr *) &this->address,
&tlen); // supply valid max length
if (client_socket == -1) {
throw "Error accepting client";
}
//do operation
}
else
{
// handle any failure except timeout here
}
}
}
Related
For my project I am unable to debug the program so i cannot be sure as to why this error occurs.
My server, which is hosted on c# is failing to connect to server on localhost.
Instead of it sending back a "connection" signal to my server, it never connects, I think the code is written well and I can't see any errors, maybe i made a careless mistake somewhere
Also, I HAVE to use gethostbyname instead of getaddrinfo
winsock namespace:
SOCKET WinSock::ConnectToServer(PCHAR IP, USHORT Port)
{
WSADATA WSA;
if (WSAStartup(MAKEWORD(2, 0), &WSA))
{
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s != SOCKET_ERROR)
{
hostent *Host = gethostbyname(IP);
if (Host != ERROR)
{
SOCKADDR_IN Addr;
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
Addr.sin_addr.s_addr = NULL;
if (bind(s, PSOCKADDR(&Addr), sizeof(Addr)) > 0)
{
return s;
}
}
}
}
return FALSE;
}
BOOL WinSock::SendData(SOCKET s, PBYTE Packet)
{
DWORD PacketSize = lstrlenA(PCHAR(Packet));
if (send(s, PCHAR(&PacketSize), 8, 0) > NULL)
{
if (send(s, PCHAR(Packet), PacketSize, 0) > NULL)
{
return TRUE;
}
}
return FALSE;
}
main method:
int main()
{
char key = 1;
SOCKET S = WinSock::ConnectToServer(0, 55480);
while(true)
{
WinSock:SendData(S, (PBYTE)key);
}
}
if (bind(s, PSOCKADDR(&Addr), sizeof(Addr)) > 0)
The description of this code is that it is supposed to connect to a server. But the problem is that bind() does not connect to any server. It only links the socket to a local port. This is what servers that listen on sockets do. This is, presumably, the same port that the server already opened, hence the bind() fails. If the server wasn't listening bind() will, ironically, succeed. But it won't be connect to anything, anyway.
You want to use connect() and not bind().
Additionally, I have to note that if this function creates a socket first, but then fails to establish a connection for this or any other reason it will return an error indication but fail to close the socket, thus leaking a socket descriptor. You must fix this bug, too.
You are not actually making a connection to the server. You are calling bind() to bind the client socket to a local port 55480, but that does not create a connection. You need to instead call connect() to connect the client socket to the remote port 55480.
Also, your SendData() is coded wrong. It is telling send() to send 8 bytes for the PacketSize, but a DWORD is only 4 bytes in size. And send() does not return NULL on failure. And send() is not guaranteed to send all of the requested bytes, so you need to call it in a loop. And it is customary to send multi-byte integers in network byte order (big endian).
Also, you have coded SendData() to expect a null-terminated C-style string, but that is not what your main() is actually passing in to it.
Try something more like this:
bool WinSock::Init()
{
WSADATA WSA;
return (WSAStartup(MAKEWORD(2, 0), &WSA) == 0);
}
bool WinSock::Cleanup()
{
return (WSACleanup() == 0);
}
SOCKET WinSock::ConnectToServer(const char *IP, unsigned short Port)
{
hostent *Host = gethostbyname(IP);
if ((Host != NULL) && (Host->h_addrtype == AF_INET)
{
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s != INVALID_SOCKET)
{
SOCKADDR_IN Addr = {};
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
Addr.sin_addr.s_addr = * (u_long*) Host->h_addr;
if (connect(s, PSOCKADDR(&Addr), sizeof(Addr)) != SOCKET_ERROR)
{
return s;
}
closesocket(s);
}
}
return INVALID_SOCKET;
}
bool WinSock::Close(SOCKET s)
{
return (closesocket(s) == 0);
}
bool WinSock::SendData(SOCKET s, const void* Data, DWORD DataSize)
{
const char *ptr = (const char*) Data;
while (DataSize > 0)
{
int numSent = send(s, ptr, DataSize, 0);
if (numSent == SOCKET_ERROR) return false;
ptr += numSent;
DataSize -= numSent;
}
return true;
}
bool WinSock::SendData(SOCKET s, const char *Packet)
{
DWORD PacketSize = lstrlenA(Packet);
DWORD tmp = htonl(PacketSize);
if (!SendData(s, &tmp, sizeof(tmp)) return false;
return SendData(s, Packet, PacketSize);
}
int main()
{
if (WinSock::Init())
{
const char *key = "1";
SOCKET S = WinSock::ConnectToServer(NULL, 55480);
if (s != INVALID_SOCKET)
{
while (true)
{
WinSock:SendData(S, key);
}
WinSock::Close(s);
}
WinSock::Cleanup();
}
return 0;
}
I'm working on a c++ class that acts as a high-level wrapper around sockets in linux. While testing it, I purposely made the server's accept() call time out by having the client application sleep for a few seconds before calling connect().
However, after the server times out, the client application is still able to call connect() and send data without detecting an error. This is obviously a problem, because the server is not receiving the data, so the client should know the connection failed.
Here is my code. The server app calls Socket::accept_connection() and the client app sleeps and then calls Socket::connect_to().
// Accept a connection on the server side with a timeout
Socket *Socket::accept_connection(double timeout) {
Socket *new_connection = NULL;
socklen_t sin_size;
struct sockaddr_storage client_address; // Client's address
struct sockaddr_in client_port_address; // Client's port
char s[INET6_ADDRSTRLEN];
sin_size = sizeof client_address;
fd_set rfds;
struct timeval timeout_structure;
timeout_structure.tv_sec = (long)(timeout);
timeout_structure.tv_usec = int((timeout - timeout_structure.tv_sec) * 1e6);
struct timeval *timeout_ptr = NULL;
if(timeout > 0)
timeout_ptr = &timeout_structure;
// Loop until the timeout has been reached
while(true) {
FD_ZERO(&rfds);
FD_SET(socket_desc, &rfds);
if(select(socket_desc + 1, &rfds, NULL, NULL, timeout_ptr) > 0) {
int client_sock = accept(socket_desc, (struct sockaddr *)&client_address, &sin_size);
if(client_sock == -1) {
// Failed to connect
connected = false;
continue;
} else {
// Connected
inet_ntop(client_address.ss_family, get_in_addr((struct sockaddr *)&client_address), s, sizeof s);
getpeername(client_sock, (struct sockaddr*)&client_port_address, &sin_size);
int client_port = ntohs(client_port_address.sin_port);
// ...
}
} else {
// Timed out
connected = false;
std::cout << "accept() timed out\n";
break;
}
}
return new_connection;
}
// Connect to the given ip address and port
bool Socket::connect_to(std::string server_ip, int server_port, double timeout) {
connected = false;
// Create the socket and allocate memory for reading in data
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
struct timeval timeout_structure;
timeout_structure.tv_sec = (long)(timeout);
timeout_structure.tv_usec = int((timeout - timeout_structure.tv_sec) * 1e6);
struct timeval *timeout_ptr = NULL;
if(timeout > 0)
timeout_ptr = &timeout_structure;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(server_ip.c_str(), std::to_string(server_port).c_str(), &hints, &servinfo)) != 0) {
fprintf(stderr, "Socket error: connect_to, getaddrinfo: %s\n", gai_strerror(rv));
throw;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((socket_desc = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("Socket error: connect_to, socket");
continue;
}
int flags = 0, error = 0, ret = 0;
fd_set rset, wset;
socklen_t len = sizeof(error);
//clear out descriptor sets for select
//add socket to the descriptor sets
FD_ZERO(&rset);
FD_SET(socket_desc, &rset);
wset = rset; //structure assignment ok
//set socket nonblocking flag
if((flags = fcntl(socket_desc, F_GETFL, 0)) < 0)
continue;
if(fcntl(socket_desc, F_SETFL, flags | O_NONBLOCK) < 0)
continue;
//initiate non-blocking connect
if(ret = connect(socket_desc, p->ai_addr, p->ai_addrlen) == -1) {
if (errno != EINPROGRESS) {
close(socket_desc);
perror("Socket error: connect_to, could not connect");
continue;
}
}
if(ret != 0) { // If connect did not succeed right away
// We are waiting for connect to complete now
if((ret = select(socket_desc + 1, NULL, &wset, NULL, timeout_ptr)) < 0)
return false;
if(ret == 0){ //we had a timeout
errno = ETIMEDOUT;
return false;
}
//we had a positive return so a descriptor is ready
if(FD_ISSET(socket_desc, &rset) || FD_ISSET(socket_desc, &wset)){
if(getsockopt(socket_desc, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error != 0)
return false;
} else
return false;
if(error){ //check if we had a socket error
errno = error;
return false;
}
}
//put socket back in blocking mode
if(fcntl(socket_desc, F_SETFL, flags) < 0)
return false;
break;
}
if(p == NULL) {
fprintf(stderr, "Socket error: connect_to, failed to connect\n");
socket_desc = 0;
return false;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s);
freeaddrinfo(servinfo); // all done with this structure
connected = true;
return connected;
}
This is normal, not a problem.
TCP maintains a listen backlog queue into which connections are placed that have been completed by the TCP stack but not yet accepted by the application.
TCP maintains a socket receive buffer per socket into which data is placed that has arrived from the peer and not yet been read by the application.
the client should know the connection failed.
It didn't fail. The server can accept it and read the data.
int tcp_sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in remoteaddr;
struct sockaddr_in localAddr;
short local_port = 22222;
short remote_port = 33333;
// local addr
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons(local_port);
localAddr.sin_addr.s_addr = 0xC0A80AA5; // we don't give a shit
int addrLen = sizeof(struct sockaddr_in);
//Now bind TCP to local addr
int result = bind(tcp_sock,(struct sockaddr*)&localAddr,addrLen);
if (result < 0)
{
perror("\nbind failed");
close(tcp_sock);
return -1;
}
result = connect(tcp_sock, (struct sockaddr*)&remoteaddr, sizeof(struct sockaddr_in));
printf("\nConnect returned %d, error no: %d", result, errno);
Here the connect() call fails after a long time. Is there any way that I can make connect function return after a time of my choice? I tried calling close() from another thread but this doesn't change anything.
Put the socket into non-blocking mode before calling connect(), then you can use select() to specify a timeout. select() will tell you whether the connection succeeds or times out. If successful, you can put the socket back into blocking mode, if you want. If failed/timeout, close the socket instead.
int tcp_sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
...
int flags = fcntl(tcp_sock, F_GETFL, 0);
fcntl(tcp_sock, F_SETFL, flags | O_NONBLOCK);
int errCode = 0;
result = connect(tcp_sock, ...);
if (result < 0)
{
errCode = errno;
if (errCode == EINPROGRESS)
{
fd_set wfd;
FD_ZERO(&wfd);
FD_SET(tcp_sock, &wfd);
struct timeval timeout;
timeout.tv_sec = ...;
timeout.tv_usec = ...;
result = select(tcp_sock+1, NULL, &wfd, NULL, &timeout);
if (result > 0)
{
socklen_t len = sizeof(errCode);
result = getsockopt(tcp_sock, SOL_SOCKET, SO_ERROR, &errCode, &len);
if (result < 0)
errCode = errno;
else
result = (errCode == 0) ? 0 : -1;
}
else if (result == 0)
{
errCode = ETIMEDOUT;
result = -1;
}
else
{
errCode = errno;
}
}
}
if (result == 0)
{
// connected
fcntl(tcp_sock, F_SETFL, flags);
...
}
else
{
// error, use errCode as needed
...
}
Is there any way that I can make connect function return after a time of my choice?
Send the process a signal.
#define TIME_OUT_SECONDS (15)
void alarm_handler(int sig)
{
/* Do nothing. */
}
int main(void)
{
...
signal(alarm_handler);
alarm(TIME_OUT_SECONDS);
result = connect(tcp_sock, ...);
...
The only way to get out of connect if its taking time is to make the socket non-blocking. If its a blocking socket, you cannot get out.
Is there any way that I can make connect function return after a time of my choice?
Your choice is to mark the socket non-blocking. No other way round. Blocking means 'block' the executing thread until a event happens on the socket.You can't having blocking socket and timing out as per your needs go together.
Use, select or epoll mechanisms to monitor the sockets.
I have a server socket accepting client socket connections. Accept is in a thread
socket creation
int ServerSocket::CreateSocket(int port)
{
listenfd = 0;
struct sockaddr_in serv_addr;
unsigned long iMode = 1;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
ioctlsocket(listenfd, FIONBIO, &iMode);
if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
return 0;
}
if (listen(listenfd, 20) < 0)
{
return 0;
}
return listenfd;
}
Socket Accept
void ServerSocket::AcceptClients_1(void * p)
{
struct sockaddr_in cli_addr;
// get a pointer to the ServerSocket object
ServerSocket * pThis = (ServerSocket *)p;
int iResult, cli_len;
cli_len = sizeof(cli_addr);
struct timeval tv = { 0, 1000 };
SOCKET s = pThis->GetSocket();
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(s, &rfds);
while (!pThis->ShutDownRequested)
{
iResult = select(s+1, &rfds, (fd_set *) 0, (fd_set *) 0, &tv);
if(iResult > 0)
{
// never comes here
SOCKET sclient = accept(s, (struct sockaddr *)&cli_addr,
&cli_len);
}
else if (iResult == 0) /// timeout
{
continue;
}
// error comes here are going to accept 2nd time
DWORD dwError = GetLastError();
return;
}
}
The code comes on select(). Returns 0 the first time but second time always returns -1 with error 10022. I don't understand why. Please help.
Make sure your pThis->GetSocket() is correctly returning the listenfd. Also, you should reinitialize cli_len = sizeof(cli_addr); before each call to accept (it's a value-result argument).
iResult=0 does not always mean timeout, for non-blocking sockets, you need to check WSAGetLastError and deal with some error codes, for example WSAEWOULDBLOCK means you need to wait next event on this socket.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx
back again (sorry)
I've created a socket C++ application, but it isn't working properly.
This is my first code:
void Network::Start()
{
this->socket = Env::GetSocket();
SOCKADDR_IN sInformation;
sInformation.sin_family = AF_INET;
sInformation.sin_addr.s_addr = INADDR_ANY;
sInformation.sin_port = htons(30000);
bind(this->socket, (SOCKADDR*) (&sInformation), sizeof(sInformation));
listen(this->socket, 10);
while (true)
{
this->DO();
}
}
And the DO function:
void Network::DO()
{
SOCKET s = SOCKET_ERROR;
sockaddr_in sock_addr;
accept(s, (sockaddr*) &sock_addr, NULL);
if (INVALID_SOCKET == s)
{
return;
}
else
{
cout << "Received connection from " << inet_ntoa(sock_addr.sin_addr);
}
}
What happens, always (even if I connect) the value s is INVALID_SOCKET. I connect via a .SWF but it doesn't accept my connection. What am I doing wrong?
You are not doing adequate error handling, and you are not using accept() correctly. Try this:
void Network::Start()
{
this->socket = Env::GetSocket();
if (this->socket == INVALID_SOCKET)
{
// error
return;
}
SOCKADDR_IN sInformation = {0};
sInformation.sin_family = AF_INET;
sInformation.sin_addr.s_addr = INADDR_ANY;
sInformation.sin_port = htons(30000);
if (bind(this->socket, (SOCKADDR*) &sInformation, sizeof(sInformation)) != 0)
{
// error
return;
}
if (listen(this->socket, 10) != 0)
{
// error
return;
}
while (true)
{
this->DO();
}
}
void Network::DO()
{
SOCKADDR_IN sock_addr = {0};
socklen_t sock_addr_len = sizeof(sock_addr);
SOCKET s = accept(this->socket, (SOCKADDR*) &sock_addr, &sock_addr_len);
if (INVALID_SOCKET == s)
{
return;
}
cout << "Received connection from " << inet_ntoa(sock_addr.sin_addr);
// use s as needed. Don't forget to call close(s) or closesocket(s)
// when finished, depending on your platform...
}
accept takes the listening socket as a parameter, and returns the newly connected socket;
socklen_t length = sizeof(sockaddr_in);
s = accept(this->socket, (sockaddr*) &sock_addr, &length);
EDIT: Just tested the program, with the socket created with AF_INET, SOCK_STREAM and sInformation cleared out;
bzero((char *) &sInformation, sizeof(sInformation));
...it seems to be running well on MacOS X and linux.