I continue learn network programming using c/c++, and after that I have created multi process tcp server, I want to create simple http server, which return static resources, I use epoll so let me show my code
first of all I use fd passing for handle request in workers
so, my main function and head process
struct Descriptors{
int sv[2];
};
class Parent{
public:
static Parent& getInstance(){
static Parent instance;
return instance;
}
Parent(Parent const&) = delete;
void operator=(Parent const&) = delete;
void addFd(int fd){
m_fd.push_back(fd);
};
void run() {
startServer();
size_t index = 0;
while(true){
struct epoll_event Events[MAX_EVENTS];
int N = epoll_wait(m_epoll, Events, MAX_EVENTS, -1);
for (size_t i =0; i < N; ++i){
if (Events[i].events & EPOLLHUP){
epoll_ctl(m_epoll, EPOLL_CTL_DEL, Events[i].data.fd, &(Events[i]));
shutdown(Events[i].data.fd,SHUT_RDWR);
close(Events[i].data.fd);
continue;
}else {
if (Events[i].data.fd == m_masterSocket) {
handleConnection();
}else {
char * arg = "1";
ssize_t size = sock_fd_write(m_fd[index], arg, 1,Events[i].data.fd);
index = (1+index) % m_fd.size();
}
}
}
}
}
private:
Parent(){
m_numCpu = sysconf(_SC_NPROCESSORS_ONLN);
}
void startServer(){
m_masterSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in SockAddr;
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(11141);
SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(m_masterSocket, (struct sockaddr *)(&SockAddr), sizeof(SockAddr));
set_nonblock(m_masterSocket);
listen(m_masterSocket, SOMAXCONN);
m_epoll = epoll_create1(0);
struct epoll_event Event;
Event.data.fd = m_masterSocket;
Event.events = EPOLLIN | EPOLLRDHUP;
epoll_ctl(m_epoll, EPOLL_CTL_ADD, m_masterSocket, &Event);
}
void handleConnection(){
int SlaveSocket = accept(m_masterSocket, 0, 0);
set_nonblock(SlaveSocket);
struct epoll_event Event;
Event.data.fd = SlaveSocket;
Event.events = EPOLLIN | EPOLLRDHUP;
epoll_ctl(m_epoll, EPOLL_CTL_ADD, SlaveSocket, &Event);
}
int m_epoll;
int m_masterSocket;
int m_numCpu;
std::vector<int> m_fd;
};
void parent(int sock){
Parent::getInstance().addFd(sock);
}
int main(int argc, char **argv){
int numCpu = sysconf(_SC_NPROCESSORS_ONLN);
std::vector<Descriptors> desc;
desc.resize(numCpu);
bool isParent = true;
for (int i = 0; i < numCpu && isParent; ++i){
std::cout << "pid my is = " << getpid() <<std::endl;
int sv[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
perror("socketpair");
exit(1);
}
pid_t forkId = fork();
switch (forkId){
case 0:{
isParent = false;
close(sv[0]);
child(sv[1]);
break;
}
case -1:
perror("fork");
exit(1);
default:
close(sv[1]);
parent(sv[0]);
break;
}
}
if (isParent){
Parent::getInstance().run();
int status;
waitpid(-1, &status, 0);
}
}
And my worker process is
void respond(int fd)
{
char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
int rcvd, fileDesc, bytes_read;
memset( (void*)mesg, (int)'\0', 99999 );
const char *ROOT = "/home/web_server/";
int RecvResult = recv(fd,mesg, 99999, MSG_NOSIGNAL);
if (RecvResult == 0 && errno != EAGAIN){
shutdown(fd,SHUT_RDWR);
close(fd);
}else if (RecvResult >0){
printf("%s", mesg);
reqline[0] = strtok (mesg, " \t\n"); // split on lexemes
if ( strncmp(reqline[0], "GET\0", 4)==0 ) // if first 4 character equal
{
reqline[1] = strtok (NULL, " \t");
reqline[2] = strtok (NULL, " \t\n");
std::cout << "reqline 1 " << reqline[1] << std::endl;
std::cout << "reqline 2 " << reqline[2] << std::endl;
if ( strncmp( reqline[2], "HTTP/1.0", 8)!=0
&& strncmp(reqline[2], "HTTP/1.1", 8 ) !=0 )
{
write(fd, "HTTP/1.0 400 Bad Request\n", 25);
}
else
{
if ( strncmp(reqline[1], "/\0", 2)==0 )
reqline[1] = "/index.html";
strcpy(path, ROOT);
strcpy(&path[strlen(ROOT)], reqline[1]);
printf("file: %s\n", path);
if ( (fileDesc=open(path, O_RDONLY))!=-1 )
{
send(fd, "HTTP/1.0 200 OK\n\n", 17, 0);
while ( (bytes_read=read(fileDesc, data_to_send, BYTES))>0 )
write (fd, data_to_send, bytes_read);
}
else write(fd, "HTTP/1.0 404 Not Found\n", 23);
}
}
}
shutdown(fd,SHUT_RDWR);
close(fd);
}
void child(int sock)
{
int fd;
char buf[16];
ssize_t size;
sleep(1);
for (;;) {
size = sock_fd_read(sock, buf, sizeof(buf), &fd);
if (size <= 0)
break;
if (fd != -1) {
respond(fd);
}
}
printf("child processes is end\n");
}
And when I go in browser http://127.0.0.1:11141/ it is ok, and I get index.html, but when I run in apache benchmark, as
ab -n 10 -c 10 http://127.0.0.1:11141/
I get answer as
This is ApacheBench, Version 2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)...apr_socket_recv: Connection reset by peer (104)
Total of 2 requests completed
I don't understand where is my error, because I I think that my server in theory(because using epoll ) have to resolved C10K problem. but on the practice, my server can not resolved 10 connection. Could you help me please?
Thank you for useful links and any advices!
UPDATE
When I run as
strace -f ./server 2> error.txt
in end of error.txt
[pid 6552] write(6, 0x7ffdbff00390, 757) = -1 EPIPE (Broken pipe)
[pid 6552] --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=6552, si_uid=1000} ---
[pid 6552] +++ killed by SIGPIPE +++
write(1, 0x7fc5ffbe3000, 83) = 83
write(1, 0x7fc5ffbe3000, 12) = 12
write(1, 0x7fc5ffbe3000, 20) = 20
write(1, 0x7fc5ffbe3000, 41) = 41
open(0x7ffdbff18e30, O_RDONLY) = 11
sendto(10, 0x403df9, 17, 0, NULL, 0) = 17
read(11, 0x7ffdbff00390, 1024) = 757
write(10, 0x7ffdbff00390, 757) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=6554, si_uid=1000} ---
+++ killed by SIGPIPE +++
So I think that problem in EPipe error, But I don't understand why...
Update
So I think that problem in close descriptor, but I don't understand how to fix it. Thank you for useful advices.
UPDATE
I Get error on function send in worker process
Seems I found my error, right version function void :
void respond(int fd)
{
char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
int rcvd, fileDesc, bytes_read;
memset( (void*)mesg, (int)'\0', 99999 );
const char *ROOT = "/home/web_server/";
int RecvResult = recv(fd,mesg, 99999, MSG_NOSIGNAL);
//EAGAIN - "there is no data available right now, try again later
if (RecvResult == 0 && errno != EAGAIN){
shutdown(fd,SHUT_RDWR);
close(fd);
std::cout << "error recv" << std::endl;
return;
}else if (RecvResult >0){
printf("%s", mesg);
reqline[0] = strtok (mesg, " \t\n"); // split on lexemes
if ( strncmp(reqline[0], "GET\0", 4)==0 ) // if first 4 character equal
{
reqline[1] = strtok (NULL, " \t");
reqline[2] = strtok (NULL, " \t\n");
std::cout << "reqline 1 " << reqline[1] << std::endl;
std::cout << "reqline 2 " << reqline[2] << std::endl;
if ( strncmp( reqline[2], "HTTP/1.0", 8)!=0
&& strncmp(reqline[2], "HTTP/1.1", 8 ) !=0 )
{
send(fd, "HTTP/1.0 400 Bad Request\n", 25 , MSG_NOSIGNAL);
}
else
{
if ( strncmp(reqline[1], "/\0", 2)==0 )
reqline[1] = "/index.html";
strcpy(path, ROOT);
strcpy(&path[strlen(ROOT)], reqline[1]);
printf("file: %s\n", path);
if ( (fileDesc=open(path, O_RDONLY))!=-1 )
{
send(fd, "HTTP/1.0 200 OK\n\n", 17, MSG_NOSIGNAL);
while ( (bytes_read=read(fileDesc, data_to_send, BYTES))>0 )
{
if (bytes_read != -1)
send (fd, data_to_send, bytes_read, MSG_NOSIGNAL);
}
}
else send(fd, "HTTP/1.0 404 Not Found\n", 23, MSG_NOSIGNAL);
}
shutdown(fd,SHUT_RDWR);
close(fd);
}
}else {
std::cout << "Client disconnected unexpect" << std::endl;
}
}
Problem was that , that I close socket , and after that I try to read from this socket.
Related
void modfd(const int& epollfd, const int& fd)
{
epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET | EPOLLONESHOT | EPOLLRDHUP;
epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
}
void Worker::work()
{
while (true)
{
len = recv(connfd, temp, sizeof(temp), NULL);
if (len == -1 && errno == EAGAIN)
{
break;
}
else if (len == 0)
{
std::cout << "errno:" << errno << " " << connfd << std::endl;
//modfd(epollfd, connfd);
}
if (totle + len < sizeof(buf))
{
memcpy(buf + totle, temp, len);
totle += len;
}
}
//Should I register here?
modfd(epollfd, connfd);
}
If the above non-blocking and registered event functions have no errors, when should I use modFd?
To be precise, this problem only occurs in webbench. When I initiate the connection alone, the program seems to have no problem.
I have the following code, which crashes my program, upon calling FD_SET.
void handleEvents(DNSServiceRef service, const int32_t timeout)
{
if (!service)
return;
const int fd = DNSServiceRefSockFD( service );
const int nfds = fd + 1;
if (fd < 0)
return;
int32_t result = servus::Result::PENDING;
while(result == servus::Result::PENDING)
{
fd_set fdSet;
FD_ZERO( &fdSet );
FD_SET( fd, &fdSet ); /// < The crash occurs here
const int result = ::select( nfds, &fdSet, 0, 0, 0);
switch (result)
{
case 0: // timeout
return;
case -1: // error
std::cerr << "Select error: " << strerror( errno ) << " (" << errno
<< ")" << std::endl;
if( errno != EINTR )
{
withdraw();
return;
}
break;
default:
if(FD_ISSET( fd, &fdSet ))
{
const auto error = DNSServiceProcessResult(service);
if(error != kDNSServiceErr_NoError)
{
std::cerr << "DNSServiceProcessResult error: " << error << std::endl;
withdraw();
return;
}
}
break;
}
}
}
The crash log is :
Exception Type: EXC_GUARD
Exception Codes: 0x6000000000000012, 0x0000000000000002
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: LIBSYSTEM, [0x2]
External Modification Warnings:
Debugger attached to process.
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x00007fff6d62d96e os_fault_with_payload + 10
1 libsystem_kernel.dylib 0x00007fff6d62e451 __darwin_check_fd_set_overflow.cold.2 + 31
2 libsystem_kernel.dylib 0x00007fff6d61967c __darwin_check_fd_set_overflow + 68
3 score 0x00000001004f097e handleEvents(_DNSServiceRef_t*, int) + 302
I really don't understand where are things going wrong - the "critical chain" that leads to the crash seems to be
const int fd = DNSServiceRefSockFD( service );
const int nfds = fd + 1;
int result = 0;
fd_set fdSet;
FD_ZERO( &fdSet );
FD_SET( fd, &fdSet ); /// < The crash occurs here
result = ::select( nfds, &fdSet, 0, 0, 0);
fd_set fdSet;
FD_ZERO( &fdSet );
FD_SET( fd, &fdSet ); /// < or here
select() now returns with errno set to EINVAL when nfds is greater than FD_SETSIZE. Use a smaller value for nfds or compile with -D_DARWIN_UNLIMITED_SELECT.
The actual issue in this case was that I was having too many file descriptors open, which can be solved by increasing the rlimit with the following code:
void setup_min_fd(int min_fds)
{
struct rlimit rlim;
if (getrlimit(RLIMIT_NOFILE, &rlim) != 0)
return;
if (rlim.rlim_cur > rlim_t(min_fds))
return;
rlim.rlim_cur = rlim.min_fds;
setrlimit(RLIMIT_NOFILE, &rlim);
}
I'm trying to create an app which would accept many connections from clients at the same time and it works for me, but it also should download those files at the same time. In this version of server, even if clients are connected simultaneously, files are written one by one.
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <ctime>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int winsock_result = WSAStartup(MAKEWORD(2,2), &wsaData);
if(winsock_result != 0)
{
exit(1);
}
SOCKET server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(server_socket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
int const max_clients = 100;
int client_socket[max_clients];
for (int i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
char* ip_address = "127.0.0.1";
int port = 6666;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_address);
int server_sizeof = sizeof(server);
int opt = TRUE;
if( setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
if(bind(server_socket,(SOCKADDR *)&server, server_sizeof) == SOCKET_ERROR)
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
if(listen(server_socket, 5) == SOCKET_ERROR)
{
std::cout << "Nasluchiwanie portu nieudane." << std::endl;
}
else
{
std::cout << "Nasluchiwanie portu " << port << " udane." << std::endl << std::endl;
}
int const buffer_size = 512;
char buffer[buffer_size];
int max_socket_descriptor, socket_descriptor;
int downloaded_files = 1;
fd_set readfds;
while(true)
{
FD_ZERO(&readfds);
FD_SET(server_socket, &readfds);
max_socket_descriptor = server_socket;
for (int i = 0 ; i < max_clients ; i++)
{
socket_descriptor = client_socket[i];
if(socket_descriptor > 0)
{
FD_SET( socket_descriptor, &readfds);
}
if(socket_descriptor > max_socket_descriptor)
{
max_socket_descriptor = socket_descriptor;
}
}
if ((select( max_socket_descriptor + 1, &readfds, NULL, NULL, NULL) < 0) && (errno != EINTR))
{
std::cout << "Blad funkcji select." << std::endl;
}
if (FD_ISSET(server_socket, &readfds))
{
int new_sockfd;
if ((new_sockfd = accept(server_socket,(SOCKADDR *)&server, &server_sizeof)) == SOCKET_ERROR)
{
std::cout << "Otrzymanie deskryptora nieudane." << std::endl;
}
else
{
for (int i = 0; i < max_clients; i++)
{
if( client_socket[i] == 0 )
{
client_socket[i] = new_sockfd;
std::cout << "Dodawanie do listy socketow jako numer " << i << std::endl;
break;
}
}
}
}
for (int i = 0; i < max_clients; i++)
{
socket_descriptor = client_socket[i];
if (FD_ISSET( socket_descriptor, &readfds))
{
struct sockaddr_in client_address;
char filename[buffer_size];
std::stringstream ip_filename;
ip_filename << "plik" << downloaded_files << "_" << inet_ntoa(client_address.sin_addr);
strcpy(filename, ip_filename.str().c_str());
std::cout << "Nazwa pliku (IP klienta): " << filename << std::endl;
FILE* file;
file = fopen(filename, "wb");
const clock_t begin_time = clock();
int received_size;
do
{
memset(buffer, 0, buffer_size);
received_size = recv(socket_descriptor, buffer, buffer_size, 0);
if (received_size == 0 || received_size == -1)
{
break;
}
fwrite(buffer, sizeof(char), received_size, file);
}
while (received_size != 0);
fclose(file);
std::cout << "Czas wysylania pliku: " << float( clock () - begin_time ) / CLOCKS_PER_SEC << " sekund." << std::endl << std::endl;
closesocket(socket_descriptor);
client_socket[i] = 0;
downloaded_files++;
}
}
}
closesocket(server_socket);
WSACleanup();
system("pause");
return 0;
}
What should I do to make them write many at the same time? I've tried many modifications of the code above but every time I can't get wanted result.
For example:
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <ctime>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
int winsock_result = WSAStartup(MAKEWORD(2,2), &wsaData);
if(winsock_result != 0)
{
exit(1);
}
SOCKET server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(server_socket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
int const max_clients = 100;
int client_socket[max_clients];
for (int i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
char* ip_address = "127.0.0.1";
int port = 6666;
SOCKADDR_IN server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_address);
int server_sizeof = sizeof(server);
int opt = TRUE;
if( setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
if(bind(server_socket,(SOCKADDR *)&server, server_sizeof) == SOCKET_ERROR)
{
closesocket(server_socket);
WSACleanup();
exit(1);
}
if(listen(server_socket, 5) == SOCKET_ERROR)
{
std::cout << "Nasluchiwanie portu nieudane." << std::endl;
}
else
{
std::cout << "Nasluchiwanie portu " << port << " udane." << std::endl << std::endl;
}
int const buffer_size = 512;
char buffer[buffer_size];
int max_socket_descriptor;
int downloaded_files = 1;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(server_socket, &readfds);
max_socket_descriptor = server_socket;
while(true)
{
if ((select( max_socket_descriptor + 1, &readfds, NULL, NULL, NULL) < 0) && (errno != EINTR))
{
std::cout << "Blad funkcji select." << std::endl;
}
for (int i = 0 ; i < max_clients ; i++)
{
if(FD_ISSET(server_socket, &readfds))
{
int new_sockfd;
if ((new_sockfd = accept(server_socket,(SOCKADDR *)&server, &server_sizeof)) == SOCKET_ERROR)
{
std::cout << "Otrzymanie deskryptora nieudane." << std::endl;
}
else
{
for (int i = 0; i < max_clients; i++)
{
if( client_socket[i] == 0 )
{
client_socket[i] = new_sockfd;
FD_SET( client_socket[i], &readfds);
if(client_socket[i] > max_socket_descriptor)
{
max_socket_descriptor = client_socket[i];
}
std::cout << "Dodawanie do listy socketow jako numer " << i << std::endl;
break;
}
}
}
}
if(FD_ISSET(client_socket[i], &readfds))
{
struct sockaddr_in client_address;
char filename[buffer_size];
std::stringstream ip_filename;
ip_filename << "plik" << downloaded_files << "_" << inet_ntoa(client_address.sin_addr);
strcpy(filename, ip_filename.str().c_str());
std::cout << "Nazwa pliku (IP klienta): " << filename << std::endl;
FILE* file;
memset(buffer, 0, buffer_size);
int received_size;
received_size = recv(client_socket[i], buffer, buffer_size, 0);
if (received_size <= 0)
{
closesocket(client_socket[i]);
FD_CLR(client_socket[i], &readfds);
client_socket[i] = 0;
break;
}
else
{
file = fopen(filename, "ab");
fwrite(buffer, sizeof(char), received_size, file);
fclose(file);
}
downloaded_files++;
}
}
}
closesocket(server_socket);
WSACleanup();
system("pause");
return 0;
}
I thought about opening and closing those files every received packet and appending every packet to them, but I really don't have idea how to do it. The example of modified code was meant to do it, but it doesn't work.
I'm forbidden to use other processes and threads than the main one, so I'm kinda helpless now. Thanks for your help.
You have the basic loop with select in place, which is good.
accept is already (mostly) non-blocking. You just need to turn on non-blocking mode on the client sockets and then you'll be able to handle multiple client reads, writes and accepts in your main select loop.
You can have a vector of client-specific data per client, with each entry containing the client socket, the opened file and any other client-specific state.
After the accept, you create a new client entry and add it to the vector. Then in the main loop you do FD_SET for accept and all client's reads and writes. After the select, you inspect the the FD sets and handle them one by one. For best performance you will want your file I/O also in non-blocking mode, but for this assignment that's probably overkill.
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;
}
}
}