we have the exercise to program a webserver in object oriented style. So we created a class for WinSockets. We wanted to loop the main part (from accept till send) to handle connections one by one (just to start up; multithreading will be implemented later).
Problem: The first time, a connection got established everything is fine, but then, the server doesn't wait for the next connection to accept. It says, it got a connection, but that descriptor throws an error, with the errornr "No Error".
main:
NetInterface *socket;
#ifdef __unix__
socket = new UnixSocket();
#elif __WIN32__ || _MSC_VER
socket = new WinSocket();
#else
printf("Ihr System wird nicht Unterstützt");
#endif
socket->socketInit(PORT);
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
char *their_addr = socket->akzeptieren();
if(their_addr == NULL) {
continue;
}
printf("server: got connection from %s\n", s);
socket->empfangen();
cout << socket->getInPacket() << endl;
}
WinSocket
class WinSocket : virtual public NetInterface
{
private:
WSADATA wsaData;
int iResult;
SOCKET sockfd;
SOCKET new_fd;
struct addrinfo *servinfo;
struct addrinfo hints;
struct addrinfo *p;
int iSendResult;
string incoming;
int recvbuflen开发者_高级运维;
char s[INET6_ADDRSTRLEN];
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
int rv;
public:
WinSocket();
int socketInit(const char *port);
char *akzeptieren();
void empfangen();
void senden(string s);
string getInPacket();
void *get_in_addr(struct sockaddr *sa);
};
[....]
char *WinSocket::akzeptieren(){
sin_size = sizeof(their_addr);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == INVALID_SOCKET) {
perror("accept");
return NULL;
}
inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
return s;
}
I think you're confused. You should normally have 2 sockets: 1 for accepting connections (you already have this one) and 1 for exchanging data (returned as new_fd
from call to accept()
in WinSocket:akzeptieren()
).
In most frameworks, a big distinction is made between listener sockets and stream sockets:
// oversimplified interface.
class Listener
{
public:
Listener ( const std::string& host, const unsigned short port );
Stream * accept ();
};
// oversimplified interface.
class Stream
{
public:
const std::string peer () const;
size_t send ( const void * data, size_t size );
size_t recv ( void * data, size_t size );
};
So, your code should look like:
const std::string host = "127.0.0.1";
const unsigned short port = 1234;
Listener listener(host, port);
while ((stream = listener.accept())
{
std::cout
<< "Connection from '" << stream->peer() << "'."
<< std::endl;
stream->send("Hello, world!", 13);
delete stream; // close and shutdown.
}
Then, you can have:
class WinListener;
class WinStream;
And make the whole thing multi-threaded.
Note: this seems to be a requirement (assignment?), so I won't suggest that you do otherwise. However, in a real production system, this is not a good server design. You may eventually want to read about the I/O completion port, epoll and kqueue subsystems for efficient asynchronous I/O.
精彩评论