I'm new to tcp socket with c++. I am trying to send a int array over the socket. I write my own client and socket(Both run on winOS). To make I can receive the int array type, I set the recvbuffer as int[] type and force it change to char inside the recv() function. This is part of the code of server:
int recvbuf[6];
and
iResult = recv(ClientSocket, (char *)&recvbuf, recvbuflen, 0);
The result is good, I can print out all the six numbers, which means my client works well. HOWEVER, when I switch the server to another one, which was built-in a sdk and running on linux, I can no longer access those numbers.
For the sdk, I have a I/O looks like this:
typedef BYTE char
unsigned int getData(BYTE * data, unsigned int len)
{
if (_dataFlag == 1)
{
if (len <= DATA_LENGTH)
{
memcpy(data, _receivedData, len);
_dataFlag = 0;
return len;
}
else
{
memcpy(data, _receivedData, DATA_LENGTH);
_dataFlag = 0;
return DATA_LENGTH;
}
}
return 0;
}
The way I access the _socketData is:
iResult = _tcpSocket.getData(_socketData, MSG_LEN);
int *ptr = (int *)&_socketData;
And use ptr[i] (i = 0 ... 5) to access the numbers. But it doesn't work, I don't get what I want. Could you guys please solve my problem, thx.
There is code how I send int array thru Client:
while (1)
{
ifstream infile;
infile.open(open_path);
if (!infile)
cout << "error" << endl;
string str;
double temp;
int length;
int array[6];
cout << "store to vector" << endl;
vector<double> ve;
while (infile >> temp)
{
ve.push_back(temp);
}
for (int i = 0; i < ve.size(); i++)
{
array[i] = ve[i] * 10000;
}
iResult = send(ConnectSocket, (char*)array, (int)sizeof(array), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
else {
cout << "success" << endl;
Sleep(500);
}
}
Related
I have wrote a simple program that is supposed to send UDP Packages with changing length. The sizes of UDP packets can change anytime.
The user can input through command line the port number and the minimum and maximum length of the message. At the first 32 bits of the payload is the UDP Packet Number.
I used the sendto() function and I am receiving a valid return number but when I try to verify it using a UDP Server program (for example SocketTest) I cannot seeany data on the other end.
Following is my code :
#define DEFAULT_PORT 355
int Port = DEFAULT_PORT; // Port to send data to
int Max_Length = 100, Min_Length = 8; //default values
static const char alphanum[] =
"0123456789"
"!##$%^&*"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
int stringLength = sizeof(alphanum);
char genRandom()
{
return alphanum[rand() % stringLength];
}
void usage()
{
cout << "-m:int Define minimum UDP packet size" << endl;
cout << " -M:int Define maximum UDP packet size" << endl;
cout << " -p:int Define remote port" << endl;
}
void ValidateArgs(int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++)
{
if ((argv[i][0] == '-'))
{
switch (argv[i][1])
{
case 'm':
if (strlen(argv[i]) > 3) {
Min_Length = (double)atoi(&argv[i][3]);
}
break;
case 'M':
if (strlen(argv[i]) > 3) {
Max_Length = (double)atoi(&argv[i][3]);
}
break;
case 'p':
if (strlen(argv[i]) > 3) {
Port = atoi(&argv[i][3]);
}
break;
default:
usage();
break;
}
}
}
}
int main(int argc, char **argv)
{
sockaddr_in my_addr;
ValidateArgs(argc, argv);
WSADATA wsd;
int Result = WSAStartup(MAKEWORD(2, 2), &wsd);
if (Result != NOERROR) {
cout << "WSAStartup Failed!" << endl;
exit(0);
}
SOCKET sock;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
cout << "Socket Failer with error: " << WSAGetLastError() << endl;
WSACleanup();
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = inet_addr("192.68.0.31");
my_addr.sin_port = htons((short)Port);
string data = "";
/*Get a Random String Length*/
random_device seeder;
int UDP_Packet_number = 1;
string buffer_data;
mt19937 engine(seeder());
uniform_int_distribution<int> dist(Min_Length, Max_Length);// user input from command line
int StrLen = dist(engine);
while (true) {
/*Get aRandom String*/
for (int i = 0; i < StrLen; ++i)
{
data += genRandom();
}
srand(time(0));
StrLen = dist(engine);
char numbr_pkg[4];
numbr_pkg[0] = (UDP_Packet_number >> 24) & 0xff;
numbr_pkg[1] = (UDP_Packet_number >> 16) & 0xff;
numbr_pkg[2] = (UDP_Packet_number >> 8) & 0xff;
numbr_pkg[3] = UDP_Packet_number & 0xff;
/*First 32 Bits is the packet Number*/
for (int i = 0; i < 4; i++) {
buffer_data += numbr_pkg[i];
}
buffer_data += data;
data = "";
int result = sendto(sock, buffer_data.c_str(), buffer_data.length(), 0, (SOCKADDR *)&my_addr, sizeof(my_addr));
//cout << result << " " << buffer_data.length() << endl;
buffer_data = "";
UDP_Packet_number++;
}
return 0;
}
Can you please tell me what am I doing wrong? I am trying to find a solution for a long time.
I'm having an issue with winsock on windows 8.1 where recv keeps returning 0 randomly. I'm running both client and server on the same machine (thus all traffic is pointed at the loopback address) and i have breakpoints on any statement on both client and server which would shut down the sockets. But when the issue occurs the server is still operating normally, and hasn't shutdown anything, while the client has hit a breakpoint that only triggers on recv returning 0 or less.
The client keeps returning 0 from recv randomly (although always at the same point in my code) when the server VS 2013 project is set to compile as a windows program (rather than a console, in order to make it produce no window, it's supposed to be silent running). The bug doesn't seem to occur when i compile the server as a console application, as I've been debugging the program in that mode and only come across this issue when i switched compilation settings.
Is there any way to launch a console window when compiling as a windows application so i can see any debug statements?
Does winsock behave differently when compiling for the console vs compiling for a windows application?
Why would the client's recv return 0, when I've not sent a shutdown signal from the server?
My code, ask if there's any more you need:
Client
void recvLoop()
{
int recievedBytes = 1;
while (running && recievedBytes > 0)
{
WORD dataSize;
WORD dataType;
int recievedBytesA = ConnectSock.Recieve(&dataSize, sizeof(WORD));
if (recievedBytesA <= 0)
{
closing = true; //breakpoint set here
attemptKillThreads();
continue;
}
int recievedBytesB = ConnectSock.Recieve(&dataType, sizeof(WORD));
if (recievedBytesB <= 0)
{
closing = true; //breakpoint set here
attemptKillThreads();
continue;
}
unique_ptr<char[]> data(new char[dataSize]);
int recievedBytesC = ConnectSock.Recieve(data.get(), dataSize);
if (recievedBytesC <= 0)
{
closing = true; //breakpoint set here - Always triggers here
attemptKillThreads();
continue;
}
//use the received data.....
}
}
When this breaks recievedBytesA = 2, recievedBytesB = 2, recievedBytesC = 0, dataType = 0, dataSize = 0
ConnectSock is a global of type ConnectSocket. here is its Recieve()
int ConnectSocket::Recieve(void *recvbuf, int recvbuflen)
{
if (sock != INVALID_SOCKET)
{
int i = recv(sock, (char *)recvbuf, recvbuflen, 0);
if ((i == SOCKET_ERROR))
{
int err = 0;
err = WSAGetLastError();
if (err != WSAEINTR)
{
//ignore WSAEINTR as that's likely to be because of a shutdown complating a bit awkwardly
cout << "error: " << err << endl;
}
}
return i;
}
return -2;
}
Server:
void sendLoop()
{
int bytessent = 0;
QueuePack tosend;
while (running)
{
tosend = sendQueue.Dequeue();
if (tosend.packType == QueuePack::EXIT || tosend.packType == 0 || tosend.dSize == 0)
{
attemptKillThreads();
continue;
}
bytessent = Connection->SendData(&tosend.dSize, sizeof(WORD));
//cout used to see what exactly is being sent, even if it is garbage when converted to text
cout << tosend.dSize << endl;
cout << bytessent << endl;
if (bytessent <= 0)
{
attemptKillThreads();
continue;
}
bytessent = Connection->SendData(&tosend.packType, sizeof(WORD));
cout << tosend.dSize << endl;
cout << bytessent << endl;
if (bytessent <= 0)
{
attemptKillThreads();
continue;
}
bytessent = Connection->SendData(tosend.bufferPtr(), tosend.dSize);
cout << tosend.bufferPtr() << endl;
cout << bytessent << endl;
if (bytessent <= 0)
{
attemptKillThreads();
}
}
if (Connection->shutdownSock(SD_SEND) == SOCKET_ERROR)
{
Connection->closeSock();
}
}
SendData is literally a wrapper for send that uses a reinterpret_cast
int SendData(void * writeBuffer, int bufferSize)
{
return send(SocketManager.clientSocket, reinterpret_cast<char *>(writeBuffer), bufferSize, 0);
}
sendQueue is a Bounded blocking queue that holds QueuePacks
QueuePacks are used to transfer data, it's size and what kind of data it is between threads. both Client and server use this as it allows me to make sure data gets to the right thread on the client
Queuepack has 2 public variables packType and dSize of type WORD.
QueuePack::QueuePack() : packType(UND), dSize(0)
{
int h = 0; //debug statement to break on - never gets hit after initial collection construction occurs
}
QueuePack::QueuePack(const WORD type, WORD size, char * data) : packType(type), dSize(size)
{
//debug test and statement to break on
if (size == 0 || type == 0)
{
int h = 0; //breakpoint - never gets hit
}
dSize = (dSize < 1 ? 1 : dSize);
_buffer = make_unique<char[]>(dSize);
memcpy(_buffer.get(), data, dSize);
}
QueuePack::QueuePack(QueuePack &other) : packType(other.packType), dSize(other.dSize)
{
//debug test and statement to break on
if (other.dSize == 0 || other.packType == 0)
{
int h = 0; //breakpoint - never gets hit
}
if (&other == this)
{
return;
}
_buffer = make_unique<char[]>(dSize);
other.buffer(_buffer.get());
}
QueuePack QueuePack::operator= (QueuePack &other)
{
// check for self-assignment
if (&other == this)
{
return *this;
}
// reuse storage when possible
if (dSize != other.dSize)
{
_buffer.reset(new char[other.dSize]);
dSize = other.dSize;
}
packType = other.packType;
other.buffer(_buffer.get());
return *this;
}
QueuePack::~QueuePack()
{
}
HRESULT QueuePack::buffer(void* container)
{
try
{
memcpy(container, _buffer.get(), dSize);
}
catch (...)
{
return E_FAIL;
}
return S_OK;
}
char * QueuePack::bufferPtr()
{
return _buffer.get();
}
When this breaks recievedBytesA = 2, recievedBytesB = 2, recievedBytesC = 0, dataType = 0, dataSize = 0
You are calling ConnectSock.Recieve() when dataSize is 0. There is nothing to read, so Receive() reports that 0 bytes were read.
You need to add a check for that condition:
unique_ptr<char[]> data(new char[dataSize]);
if (dataSize != 0) // <-- add this
{
int recievedBytesC = ConnectSock.Recieve(data.get(), dataSize);
if (recievedBytesC <= 0)
{
closing = true;
attemptKillThreads();
continue;
}
}
Your code is also assuming that Recieve() reads all bytes that are requested, it is not handling the possibility that recv() may return fewer bytes. So you need to make Recieve() call recv() in a loop to guarantee that everything requested is actually read:
int ConnectSocket::Recieve(void *recvbuf, int recvbuflen)
{
if (sock == INVALID_SOCKET)
return -2;
char *buf = static_cast<char *>(recvbuf);
int total = 0;
while (recvbuflen > 0)
{
int i = recv(sock, buf, recvbuflen, 0);
if (i == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err != WSAEINTR)
{
//ignore WSAEINTR as that's likely to be because of a shutdown complating a bit awkwardly
cout << "error: " << err << endl;
}
return -1;
}
if (i == 0)
{
cout << "disconnected" << endl;
return 0;
}
buf += i;
recvbuflen -= i;
total += i;
}
return total;
}
Same with SendData(), as send() may return fewer bytes than requested:
int SendData(void * writeBuffer, int bufferSize)
{
if (SocketManager.clientSocket == INVALID_SOCKET)
return -2;
char *buf = static_cast<char *>(writeBuffer);
int total = 0;
while (bufferSize > 0)
{
int i = send(SocketManager.clientSocket, buf, bufferSize, 0);
if (i == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err != WSAEINTR)
{
//ignore WSAEINTR as that's likely to be because of a shutdown complating a bit awkwardly
cout << "error: " << err << endl;
}
return -1;
}
buf += i;
bufferSize -= i;
total += i;
}
return total;
}
I'm really going to try to avoid posting my entire project on here - unless it's needed :)
I have a client/server program I'm writing where the client contacts the server via a UDP port, and expects to receive a packet in the format "#7777~15~3701" - the first time I connect, I get garbage in the buffer. However, once the client exits, and I launch it again, the next buffer "#7777~15~3702" comes through just fine.
int
RoutingManager::SendMessage(struct sockaddr_in toNode, char buffer[1024])
{
#if logging > 1
cout << "Sending: " << buffer << endl;
#endif
int n;
unsigned int length = sizeof(struct sockaddr_in);
//buffer = "#7777~15~3702"
n = sendto(mySocket, buffer, strlen(buffer),0,
(const struct sockaddr *)&toNode,length);
if (n < strlen(buffer))
perror("Sendto");
cout << "Sent: " << n << " bytes of data\n";
}
.. the buffer I pass in here is generated from:
//FIXED: This was the source of my issue it appears - a corrected
//implementation of this method has been included at the bottom.
char*
RoutingManager::GenerateConnectionString(struct Node n)
{
char buffer[512];
bzero(buffer,512);
sprintf(buffer, "#7777~15~%d", n.id);
cout << MYPORT << endl;
return buffer;
}
Server Output:
Sending: #7777~15~3701
Sent: 1 bytes of data
Waiting for nodes...
Client Side:
RoutingNode::GetMyID()
{
int n;
char buffer[256];
bzero(buffer,256);
unsigned int length = sizeof(struct sockaddr_in);
struct sockaddr_in from;
n = sendto(mySocket,"!", strlen("!"),0,(const struct sockaddr *)&server,length);
if (n < 0)
perror("Sendto");
//once we have our information from the manager, let's hog some cpu
//remove this crap when stuff gets more reliable
fcntl(mySocket, F_SETFL, O_NONBLOCK);
while(buffer[0] != '#')
n = recvfrom(mySocket,buffer,256,0,(struct sockaddr *)&from, &length);
if (n < 0)
perror("recvfrom");
parser.ParseMessage(buffer, fromNode, messages);
}
When I parse the message:
bool
RoutingMessage::ParseMessage(char* buffer, int &fromNode, map<int, string> &messages, const int MAX_CHARS_PER_LINE,
const int MAX_TOKENS_PER_LINE, const char* const DELIMITER)
{
#if logging > 1
cout << "Buffer: " << buffer << endl;
#endif
if (buffer[0] != '#')
{
perror("Buffer malformated!");
return false;
}
//remove the '#'
buffer++;
char buf[MAX_CHARS_PER_LINE];
strcpy(buf, buffer);
char* temp = strtok(buf, DELIMITER);
if (temp == NULL)
{
perror("Buffer malformated!");
return false;
}
fromNode = atoi(temp);
temp = strtok(NULL, DELIMITER);
vector<string> tokens;
while(temp != NULL)
{
string val(temp);
tokens.push_back(val);
temp = strtok(NULL, DELIMITER);
}
//store messages in the map: <message-type>, <message>
for (int i = 0; i < tokens.size(); i+=2)
messages.insert(pair<int, string>(atoi(tokens[i].c_str()), tokens[i+1]));
//all good
return true;
}
And output the results, I get junk:
Buffer: <junk-symbol>
Buffer malformated!: Success
Node: 0
But when the client disconnects, and I relaunch the same executable, I get:
Buffer: #7777~15~3702
Node: 7777
Message Type: 15 Message: 3702
As I'd expect. Anyone know of something I could check?
Corrected Method --
void
RoutingManager::GenerateConnectionString(struct Node n, char* buffer)
{
bzero(buffer,512);
sprintf(buffer, "#7777~15~%d", n.id);
}
The above seems to solve my issues.
The problem seems to be in GenerateConnectionString() function:
char*
RoutingManager::GenerateConnectionString(struct Node n)
{
char buffer[512];
....
return buffer;
}
It returns a pointer to a local variable.
So the returned pointer points to the stack. So the data will be corrupted later when the program uses stack from that area.
I have deamon process. Which works as server socket. And to make it listening I execute it in terminal manually : ./daemon
Now When I want to keep this on ftp server, ther I could not execute in that manner. So I want it to keep listening by deafult.
I see on goolge for how to creat it. It says that child and parent process with two fork() will work as daemon process. But I could not figure out which process ID should used where. Here is my code, Can some one please guide:
using namespace std;
void *SocketHandler(void *);
int main(int argv, char **argc)
{
int host_port = 1103;
char buf[20];
int k;
struct sockaddr_in my_addr;
int hsock;
int *p_int;
int err;
socklen_t addr_size = 0;
int *csock;
sockaddr_in sadr;
pthread_t thread_id = 0;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if (hsock == -1) {
printf("Error initializing socket %dn", errno);
goto FINISH;
}
p_int = (int *) malloc(sizeof(int));
*p_int = 1;
if ((setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char *) p_int, sizeof(int)) == -1) || (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char *) p_int, sizeof(int)) == -1)) {
printf("Error setting options %dn", errno);
free(p_int);
goto FINISH;
}
free(p_int);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(hsock, (sockaddr *) & my_addr, sizeof(my_addr)) == -1) {
fprintf(stderr, "Error binding to socket, make sure nothing else is listening on this port %dn", errno);
goto FINISH;
}
if (listen(hsock, 10) == -1) {
fprintf(stderr, "Error listening %dn", errno);
goto FINISH;
}
//Now lets do the server stuff
addr_size = sizeof(sockaddr_in);
while (true) {
printf("waiting for a connectionn\n");
csock = (int *) malloc(sizeof(int));
if ((*csock = accept(hsock, (sockaddr *) & sadr, &addr_size)) != -1) {
printf("---------------------nReceived connection from %s\n", inet_ntoa(sadr.sin_addr));
pthread_create(&thread_id, 0, &SocketHandler, (void *) csock);
pthread_detach(thread_id);
} else {
fprintf(stderr, "Error accepting %dn", errno);
}
}
FINISH:
;
}
std::pair < int, std::string > mytransform(const std::pair < std::string, int >p)
{
return std::pair < int, std::string > (p.second, p.first);
}
void *SocketHandler(void *lp)
{
int ar[10];
int result=0;
int *csock = (int *) lp;
char buf[20];
int k;
char *skp;
char *str;
char *str2;
std::stringstream ss;
std::multimap < int, std::string, std::greater < int >>dst;
std::multimap < int, std::string >::iterator rec;
std::map < std::string, int >src;
std::map < int, std::vector < std::string > >three_highest;
std::vector < std::string > writable;
std::string item;
std::ostringstream bfr;
std::string result_string;
std::istringstream iss;
std::ostringstream oss;
// std::multimap < int, std::string >::iterator it;
std::vector<std::string> most;
int max_count = 0;
int tmp=0;
int pcount = 0, ncount = 0;
char buffer[1024];
int buffer_len = 1024;
int bytecount;
int i = 0,t=0,q=0;
int j = 0;
char *ch[50] = { 0 }; /* stores references to 50 words. */
char *ch2[50] = { 0 };
char *excluded_string[50] = { 0 };
char *word = strtok(buffer, " ");
char *word2 = strtok(buffer, " ");
char *portstring1=(char *)malloc(sizeof(buffer));
char *portstring2=(char *)malloc(sizeof(buffer));
memset(buffer, 0, buffer_len);
if ((bytecount = recv(*csock, buffer, buffer_len, 0)) == -1) {
fprintf(stderr, "Error receiving data %d \n", errno);
goto FINISH;
}
printf("Received bytes %d \nReceived string %s \n ", bytecount, buffer);
word = strtok(buffer, " ");
while ((NULL != word) && (50 > i)) {
ch[i] = strdup(word);
excluded_string[j]=strdup(word);
word = strtok(NULL, " ");
skp = BoyerMoore_skip(ch[i], strlen(ch[i]) );
if(skp != NULL)
{
i++;
continue;
}
printf("exclueded : %s and %s size %d \n",excluded_string[j],ch[i],sizeof(excluded_string));
bfr << excluded_string[j] << " ";
result_string = bfr.str();
j++;
// std::cout << "string is :" << r1;
}
std::cout << "string is :" << result_string << "\n";
ss<<result_string;
while (std::getline(ss, item, ' ')) {
writable.push_back(item);
}
for (std::vector < std::string >::iterator it = writable.begin(); it != writable.end(); it++)
++src[*it];
std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()), mytransform);
rec=dst.begin();
for (auto it = dst.begin(); it != dst.end(); ++it)
std::cout << it->second << ":" << it->first << std::endl;
while (three_highest.size() < 3 && rec != dst.end()) {
three_highest[rec->first].push_back(rec->second);
rec++;
}
//std::cout << "\nthree_highest:\n";
i=0;
for (std::map < int, std::vector < std::string > >::iterator hit = three_highest.begin(); hit != three_highest.end(); ++hit) {
//std::cout << hit->first << ":";
for (std::vector < std::string >::iterator vit = (*hit).second.begin(); vit != (*hit).second.end(); vit++) {
std::cout << hit->first << ":";
std::cout << *vit << "\n";
ar[i]= hit-> first;
printf(" ar : %d \n",ar[i]);
i++;
oss << hit->first << " " << *vit << "\n";
}
}
printf( "i is :%d \n",i);
if ((bytecount = send(*csock, (char *)ar, i *sizeof(int), 0)) == -1) { // Here we cant send lenth-1. It consider exact
fprintf(stderr, "Error sending data %d\n", errno);
goto FINISH;
}
FINISH:
free(csock);
return 0;
}
You should start with a simpler problem. It seems that in this case you have issues with creating a daemon. This is a good tutorial that was very useful for me when I was learning.
Strange. I can make GET requests using the included code on my local machine, and it works like a charm. From the local machine command line, using GET -Ue 192.168.2.106:8129 I get
200 OK
Content-Length: 296
Content-Type: text/html
Client-Date: Sat, 09 Feb 2013 20:26:09 GMT
Client-Response-Num: 1
<html><body><h1>Directory</h1><a href=/.>.</a><br/><a href=/..>..</a><br/><a href=/bldg.jpg>bldg.jpg</a><br/><a href=/hello.txt>hello.txt</a><br/><a href=/world.gif>world.gif</a><br/><a href=/index.html>index.html</a><br/><a href=/testing>testing</a><br/><a href=/favicon.ico>favicon.ico</a><br/>
Wheras from the remote machine I get
200 OK
Content-Length: 328
Content-Type: text/html
Client-Aborted: die
Client-Date: Sat, 09 Feb 2013 20:25:16 GMT
Client-Response-Num: 1
X-Died: read failed: Connection reset by peer at /usr/share/perl5/LWP/Protocol/http.pm line 414.
The second one looks like it wants to work, but the wonky "X-Died" header is odd. I have a sneaking suspicion that my GetLine method is off, but I'm not quite sure. Any idea what could be causing this issue?
Main function:
int main(int argc, char* argv[])
{
// First set up the signal handler
struct sigaction sigold, signew;
signew.sa_handler = handler;
sigemptyset(&signew.sa_mask);
sigaddset(&signew.sa_mask, SIGPIPE);
signew.sa_flags = SA_RESTART;
sigaction(SIGPIPE, &signew, &sigold);
int hSocket,hServerSocket; /* handle to socket */
struct hostent* pHostInfo; /* holds info about a machine */
struct sockaddr_in Address; /* Internet socket address stuct */
int nAddressSize=sizeof(struct sockaddr_in);
char pBuffer[BUFFER_SIZE];
int nHostPort;
q = new myQueue();
// THREAD POOL!
pthread_t thread_id[NUMTHREADS];
int i=0;
for(i=0; i < NUMTHREADS; i++)
{
threadParams param;
param.a = i;
pthread_create(&thread_id[i], 0, &WorkerHandler, NULL);
}
if(argc < 2)
{
printf("\nUsage: server host-port\n");
return 0;
}
else
{
nHostPort = atoi(argv[1]);
}
printf("\nStarting server");
printf("\nMaking socket");
/* make a socket */
hServerSocket=socket(AF_INET,SOCK_STREAM,0);
if(hServerSocket == SOCKET_ERROR)
{
printf("\nCould not make a socket\n");
return 0;
}
/* fill address struct */
Address.sin_addr.s_addr=INADDR_ANY;
Address.sin_port=htons(nHostPort);
Address.sin_family=AF_INET;
printf("\nBinding to port %d",nHostPort);
int optval = 1;
setsockopt(hServerSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
/* bind to a port */
if(bind(hServerSocket,(struct sockaddr*)&Address,sizeof(Address)) == SOCKET_ERROR)
{
printf("\nCould not connect to host\n");
return 0;
}
/* get port number */
getsockname( hServerSocket, (struct sockaddr *) &Address,(socklen_t *)&nAddressSize);
printf("opened socket as fd (%d) on port (%d) for stream i/o\n",hServerSocket, ntohs(Address.sin_port) );
printf("Server\n\
sin_family = %d\n\
sin_addr.s_addr = %d\n\
sin_port = %d\n"
, Address.sin_family
, Address.sin_addr.s_addr
, ntohs(Address.sin_port));
/* establish listen queue */
if(listen(hServerSocket, 1000) == SOCKET_ERROR)
{
printf("\nCould not listen\n");
return 0;
}
while(1)
{
int socket = accept(hServerSocket, (struct sockaddr*)&Address, (socklen_t *)&nAddressSize);
q->enqueue(socket);
}
}
void handler (int status)
{
}
Handle requests on the socket:
int handleRequest(int socket)
{
cout << "handling a request..." << endl;
// Get the URL
char * line = GetLine(socket);
//char * line = "GET /bldg.jpg HTTP/1.1";
char * url;
url = strtok(line, " "); // Splits spaces between words in str
url = strtok(NULL, " "); // Splits spaces between words in str
// build filename
ostringstream fullpathstream;
fullpathstream << dirpath << url;
string fullpath = fullpathstream.str();
//Use the stat function to get the information
struct stat fileAtt;
if (stat(fullpath.c_str(), &fileAtt) != 0) //start will be 0 when it succeeds
{
cout << "File not found:" << fullpath.c_str() << endl;
writeError(socket);
return 0;
}
// Make correct filetypes
if (S_ISREG (fileAtt.st_mode))
{
printf ("%s is a regular file.\n", fullpath.c_str());
char * contentType;
if(strstr(url, ".jpg"))
{
cout << "JPEG" << endl;
contentType = "image/jpg";
}
else if(strstr(url, ".gif"))
{
contentType = "image/gif";
cout << "GIF" << endl;
}
else if(strstr(url, ".html"))
{
contentType = "text/html";
cout << "HTML" << endl;
}
else if(strstr(url, ".txt"))
{
cout << "TXT" << endl;
contentType = "text/plain";
}
else if(strstr(url, ".ico"))
{
cout << "ICO" << endl;
contentType = "image/ico";
}
serveFile(fullpath, socket, fileAtt.st_size, contentType);
}
if (S_ISDIR (fileAtt.st_mode))
{
printf ("%s is a directory.\n", fullpath.c_str());
serveDirectory(socket, url);
}
return 0;
};
GetLine function for getting the first line of the request so I knowt the requested URL:
// Read the line one character at a time, looking for the CR
// You dont want to read too far, or you will mess up the content
char * GetLine(int fds)
{
char tline[MAX_MSG_SZ];
char *line;
int messagesize = 0;
int amtread = 0;
while((amtread = read(fds, tline + messagesize, 1)) < MAX_MSG_SZ)
{
if (amtread > 0)
messagesize += amtread;
else
{
perror("Socket Error is:");
fprintf(stderr, "Read Failed on file descriptor %d messagesize = %d\n", fds, messagesize);
exit(2);
}
//fprintf(stderr,"%d[%c]", messagesize,message[messagesize-1]);
if (tline[messagesize - 1] == '\n')
break;
}
tline[messagesize] = '\0';
chomp(tline);
line = (char *)malloc((strlen(tline) + 1) * sizeof(char));
strcpy(line, tline);
//fprintf(stderr, "GetLine: [%s]\n", line);
return line;
}
I have multithreading happening, and this is where I close my sockets.
void * WorkerHandler(void *arg)
{
threadParams* params = (threadParams*)arg;
while(1)
{
int socket = q->dequeue();
handleRequest(socket);
if(close(socket) == SOCKET_ERROR)
{
printf("\nCould not close socket\n");
return 0;
}
}
}