Roger
March 31st, 1999, 09:03 PM
Hello everyone,
I am planning to write a server program using VC++.
Which project type should I use? I want to use MFC
but since it is a server program, it does not need to have any gui.
Also, it must be able to spin off multiple threads.
The server is going to use CSocket to communicate with its
clients. Is there a better way?
Or is there a skeleton main program of a server programs which
accepts a connection and does something?
In short, I have experience writing VC++ GUI program but have not done
any server program development. I just want to get started in the right
direction.
Please advise. Thanks a lot!
regards,
roger
Gozer
April 1st, 1999, 11:15 AM
Check Out The "System" section on the CodeGuru Home Page.
I saw some examples and discussion there.
Hope It Helps.
Flax
April 8th, 1999, 03:44 AM
I should use the win32 console application, and write the whole app in posix c++, has great adventage that it is multi-platform. You know exactly what's going on, think that is important in a server app. If a gui app has a memory leak, so what, but a server app, it keeps grewing cause it should run for ever ( well the uptime of NT is not that high...)
Have some source for socket btw... under windoze u must link a certain file with it.. (is named in documentation.. look for accept or something like that... )
!!! Using this file as example is fine, when modifing, copying etc... u must return it in public
!!! and the names of the authors stay in the files
/* File: Socket.h
Author: RA Scheltema
E Witteveen
Flax@beer.com
Date: Januari 8, 1999
Implementation of the java socket-class
in C++ :).
ToDo:
- Think about m_connected.
- In constructor clean up yer stuff on error.
- write(void *bytes)
Send bytes that where left over after first send.
- read(int &length)
Send bytes that where left over after first send.
*/
#ifndef _SOCKET_CLASS_
#define _SOCKET_CLASS_
#ifdef LINUX
typedef int SOCKET;
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#else // WINDOWS
#include <winsock.h>
typedef SOCKADDR_IN sockaddr_in;
#endif
#include <iostream.h>
#include "Exception.h"
#include "InetAddress.h"
#define BLOCKSIZE 1024
typedef enum {
ftp = 21, //tcp
telnet = 23, //tcp
smtp = 25, //tcp mail
time_ = 37, //tcp timeserver # name conflict with afx.h & time.h
name = 42, //tcp nameserver
nameserver = 53, //tcp domain # name-domain server
finger = 79, //tcp
http = 80, //tcp
pop = 109, //tcp postoffice
pop2 = 109, //tcp # Post Office
pop3 = 110, //tcp postoffice
nntp = 119 //tcp usenet # Network News Transfer
} SocketService;
class Socket {
public:
Socket();
// Makes an unconnected socket-instance.
// Socket(unsigned long int port) throw(Exception);
// Makes a socket-instance on localhost and port.
Socket(TString adress, unsigned short int port) throw(Exception);
// Makes a socket-instance on host and port.
~Socket();
void disconnect();
int available() throw(Exception);
// Returns the number of bytes on the socket, without blocking.
void write(void *bytes, size_t length) throw(Exception);
void *read(int &length) throw(Exception);
public:
SOCKET m_socket;
protected:
#ifdef LINUX
#else // WINDOWS
#endif
struct sockaddr_in m_address;
};
#endif
////// next file is socket.cpp
include "Socket.h"
/// Flax@beer.com
Socket::Socket() {
m_socket = -1;
}
/*
Socket::Socket(unsigned long int port) throw(Exception) {
#ifdef LINUX
Socket(InetAdress(LocalHost), port);
#else // WINDOWS
#endif
}
*/
Socket::Socket(TString address, unsigned short int port) throw(Exception) {
#ifdef LINUX
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket < 0) {
if(errno == EACCES)
throw(EXCEPTION("Permission to create a socket is denied."));
else if(errno == ENOBUFS)
throw(EXCEPTION("Insufficient number of recourses free to create a socket."));
else
throw(EXCEPTION("General failure to create a socket."));
}
memset(&m_address, 0, sizeof(struct sockaddr_in));
m_address.sin_family = AF_INET;
memcpy(&m_address.sin_addr.s_addr,
address.getAddress()->h_addr,
address.getAddress()->h_length);
m_address.sin_port = htons(port);
if (connect(m_socket,(struct sockaddr*) &m_address, sizeof(struct sockaddr_in)) == -1) {
disconnect(); // Does not work.
close(m_socket);
if (errno == ECONNREFUSED)
throw(EXCEPTION("Could not connect, due to refuse of server."));
else if (errno == ETIMEDOUT)
throw(EXCEPTION("Didn't connect, due to timeout."));
else if (errno == EADDRINUSE)
throw(EXCEPTION("Didn't connect, because address is allready in use."));
else
throw(EXCEPTION("Didn't connect, due to a general failure."));
}
#else // WINDOWS
const WORD wMinVer = 0x0101; // request WinSock v1.1 (at least)
WSADATA wsaData;
if(WSAStartup(wMinVer, &wsaData) != 0)
throw(EXCEPTION("Error in constructing Socket: got request for WinSock < v1.1."));
m_socket = socket(PF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET) {
// int error = WSAGetLastError();
throw(EXCEPTION("could not create socket."));
}
m_address.sin_family = AF_INET ;
// m_address.sin_addr.S_un.S_addr = *(unsigned long *)(address.getA()->h_addr_list[0]);
char *www = address.toChar();
m_address.sin_addr.S_un.S_addr = inet_addr(www);
delete[] www;
m_address.sin_port = htons(port);
if( SOCKET_ERROR == ::connect(m_socket, (sockaddr *)&m_address, sizeof(struct sockaddr_in))) {
// int error = WSAGetLastErro();
throw(EXCEPTION("Connection error."));
}
#endif
}
Socket::~Socket() {
disconnect();
}
void Socket::disconnect() {
shutdown(m_socket, 2);
#ifdef LINUX
close(m_socket);
#else // WINDOWS
closesocket(m_socket);
#endif
}
int Socket::available() throw(Exception) {
int recieved,
buf_size = BLOCKSIZE;
char *buf = new char[buf_size];
#ifdef LINUX
while ((recieved = recv(m_socket, buf, buf_size, MSG_PEEK)) == buf_size) {
#else // WINDOWS
while ((recieved = ::recv(m_socket, buf, buf_size, MSG_PEEK)) == buf_size) {
#endif
delete[] buf;
buf_size += BLOCKSIZE;
buf = new char[buf_size];
}
delete[] buf;
if (recieved == -1)
throw(EXCEPTION("General failure in determening size of data on the socket."));
else
return recieved;
}
void Socket::write(void *bytes, size_t length) throw(Exception) {
#ifdef LINUX
int nr_send = send(m_socket, bytes, length, 0);
if (nr_send == -1) {
if (errno == ENOBUFS)
throw(EXCEPTION("Could not send data, because of congestion of the output queue of the network interface."));
else if (errno == EFAULT)
throw(EXCEPTION("Could not send data, because of invalid data."));
else
throw(EXCEPTION("Could not send data, because of general failure."));
}
/* If not all bytes where send, send the rest.
*/
#else // WINDOWS
int nr_send = ::send(m_socket, (char FAR*) bytes, length, 0);
if (nr_send == -1) {
//int error = WSAGetLastError();
throw(EXCEPTION("Could not send data, because of general failure."));
}
/* If not all bytes where send, send the rest.
*/
#endif
}
void *Socket::read(int &length) throw(Exception) {
length = available();
void *bytes = malloc(length);
if (bytes == NULL)
throw(EXCEPTION("Could not read, because no memory could be allocated."));
#ifdef LINUX
int nr_recieved = recv(m_socket, bytes, length, 0);
if (nr_recieved == -1) {
free(bytes);
if (errno == EINTR)
throw(EXCEPTION("Could not read, because of interrupt."));
else
throw(EXCEPTION("Could not read, because of general failure."));
}
/* If not all bytes where read, read the rest.
*/
#else
int nr_recieved = ::recv(m_socket, (char FAR*) bytes, length, 0);
if (nr_recieved == -1) {
//int error = WSAGetLastError();
throw(EXCEPTION("Could not read, because of general failure."));
}
/* If not all bytes where read, read the rest.
*/
#endif
return (void *)bytes;
}
//////next file is serversocket.h
/* Class: ServerSocket
Author: RA Scheltema
E Witteveen
Flax@beer.com
Date: Januari 9, 1999
Implementation of Java's ServerSocket in
C++ :).
ToDo:
- In constructor clean up yer stuff on error.
*/
#ifndef _SERVERSOCKET_CLASS_
#define _SERVERSOCKET_CLASS_
#ifdef LINUX
typedef int SOCKET;
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#else // WINDOWS
#include <winsock.h>
typedef SOCKADDR_IN sockaddr_in;
#endif
#include "Socket.h"
#define NORMAL_BACKLOG 50
class ServerSocket {
public:
ServerSocket(unsigned short port, unsigned int backLog = 50) throw(Exception);
~ServerSocket();
Socket *_accept() throw(Exception);
void disconnect();
private:
SOCKET m_socket;
struct sockaddr_in m_address;
int m_backLog;
};
#endif
///////next file is serversocket.cpp
#include "ServerSocket.h"
ServerSocket::ServerSocket(unsigned short port, unsigned int backLog) throw(Exception) {
#ifdef LINUX
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket < 0) {
if(errno == EACCES)
throw(EXCEPTION("Permission to create a socket is denied."));
else if(errno == ENOBUFS)
throw(EXCEPTION("Insufficient number of recourses free to create a socket."));
else
throw(EXCEPTION("General failure to create a socket."));
}
memset(&m_address, 0, sizeof(struct sockaddr_in));
m_address.sin_family = AF_INET;
m_address.sin_addr.s_addr = htons(INADDR_ANY);
m_address.sin_port = htons(port);
if (bind(m_socket, (struct sockaddr *) &m_address, sizeof m_address) == -1) {
close(m_socket);
if (errno == EACCES)
throw(EXCEPTION("Permission to bind to the given adress is denied."));
else
throw(EXCEPTION("General failure in binding socket."));
}
if (listen(m_socket, backLog) == -1) {
disconnect(); // Does not work !!!!
close(m_socket);
throw(EXCEPTION("General failure in creating socket."));
}
#else // WINDOWS
const WORD wMinVer = 0x0101; // request WinSock v1.1 (at least)
WSADATA wsaData;
if(WSAStartup(wMinVer, &wsaData) != 0)
throw(EXCEPTION("Error in constructing Socket: got request for WinSock < v1.1."));
m_socket = socket(PF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET) {
disconnect();
// int error = WSAGetLastError();
throw(EXCEPTION("could not create socket."));
}
m_address.sin_family = AF_INET ;
m_address.sin_addr.S_un.S_addr = htons(INADDR_ANY);
m_address.sin_port = htons(port);
if(SOCKET_ERROR == ::bind(m_socket, (sockaddr *)&m_address, sizeof(struct sockaddr_in))) {
disconnect();
// int error = WSAGetLastErro();
throw(EXCEPTION("Connection error."));
}
if (::listen(m_socket, backLog) == SOCKET_ERROR) {
disconnect(); // Does not work !!!!
throw(EXCEPTION("General failure in creating socket."));
}
#endif
}
ServerSocket::~ServerSocket() {
disconnect();
}
Socket *ServerSocket::_accept() throw(Exception) {
SOCKET socket;
struct sockaddr_in client;
int client_len = sizeof(sockaddr_in);
#ifdef LINUX
socket = accept(m_socket, (struct sockaddr *) &client, &client_len);
if (socket == -1)
throw(EXCEPTION("General failure in accepting connection"));
#else // WINDOWS
socket = ::accept(m_socket, (struct sockaddr *) &client, &client_len);
if (socket == SOCKET_ERROR) {
//int error = WSAGetLastError();
throw(EXCEPTION("General failure in accepting connection"));
}
#endif
else {
Socket *s = new Socket();
s->m_socket = socket;
return s;
}
}
void ServerSocket::disconnect() {
#ifdef LINUX
close(m_socket);
#else // WINDOWS
closesocket(m_socket);
#endif
}
/*
void main() {
try {
ServerSocket server(4000);
}
catch(Exception e) {
cout<<e.getMessage()<<endl<<flush;
}
}
*/