Hi I am writing a simple web server in C that will just handle simple get and post requests sent from a browser. I am not that familiar with C so debugging has been painful but I have gotten it to compile but continually I am getting a err_connection_reset response from my browser when trying to view webpage. I have narrowed it down to not entering the main loop that used to listen on the open socket but it will not enter it, here is my main function
int main(int argc, char *argv[])
{
printf("in main");
int portno; // port number passed as parameter
portno = atoi(argv[1]); // convert port num to integer
if (portno < 24)
{
portno = portno + 2000;
}
else if ((portno > 24) && (portno < 1024))
{
portno = portno + 1000;
}
else
{
;
}
// Signal SigCatcher to eliminate zombies
// a zombie is a thread that has ended but must
// be terminated to remove it
signal(SIGCHLD, SigCatcher);
int sockfd; // socket for binding
int newsockfd; // socket for this connection
int clilen; // size of client address
int pid; // PID of created thread
// socket structures used in socket creation
struct sockaddr_in serv_addr, cli_addr;
// Create a socket for the connection
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error("ERROR opening socket\n");
}
// bzero zeroes buffers, zero the server address buffer
bzero((char *)&serv_addr, sizeof(serv_addr));
// set up the server address
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
// bind to the socket
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding. Did you forget to kill the last server?\n");
listen(sockfd, 5); // Listen on socket
clilen = sizeof(cli_addr); // size of client address
while (1)
{ // loop forever listening on socket
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, (socklen_t *) & clilen);
if (newsockfd < 0)
error("ERROR on accept");
// Server waits on accept waiting for client request
// When request received fork a new thread to handle it
pid = fork();
if (pid < 0)
error("ERROR on fork\n");
if (pid == 0)
{ // request received
close(sockfd);
// Create thread and socket to handle
httpthread(newsockfd, cli_addr);
exit(0);
}
else
close(newsockfd);
} /* end of while */
return 0; /* we never get here */
}
The loop executes exactly once, and then the program terminates because you call exit(0) in the parent process. When you call exit, the entire process dies, including active threads. This includes the thread that is created by calling httpthread(newsockfd, cli_addr).
Besides, the child process is closing the socket. Check that you really want to do this, and do not terminate the program inside the parent process.
Related
EDIT: Minimal, Complete, and Verifiable example is in comment lower and the code actually works, problem was in different area. Sorry for bad posting, I cannot delete it now.
I know, that there are some pages about this already, but I really tried everything and nothing works. Im having this error all the time and my code looks like this:
int server_socket, new_socket;
struct sockaddr_in server;
bzero((char *) &server, sizeof(server));
server_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if(server_socket < 0) error("ERROR opening socket");
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(port_number);
if(bind(server_socket, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) < 0) error("ERROR on binding");
if(listen(server_socket, 5) < 0) error("Failed to listen for connections.");
while(1)
{
struct sockaddr_in client;
unsigned int client_len = sizeof(struct sockaddr_in);
bzero((char *) &client, client_len);
if((new_socket = accept(server_socket, (struct sockaddr *) &client, &client_len)) < 0)
{
if(errno == EAGAIN) continue;
else error("ERROR on accept");
}
if((pid = fork()) > 0)
{ // this is parent process
close(new_socket);
}
else if(pid == 0)
{ // this is a child process that will handle an incoming request
long_pid = (long) getpid(); // current child's PID
close(server_socket);
server_socket = -1; //closing parent socket
printf("A new connection accepted from blablabla, port %d by process %ld\n", port_number, long_pid);
// ---- doing some staff, running the program
EDIT: while((msg_size = read(new_socket, received_data, BUFFER_SIZE)) >0)
// ---- when Im done:
printf("closing newsock\n");
close(new_socket); // close the new socket
new_socket = -1;
exit(0);
}
}
else error("fork() failed");
}
// close the server
printf("closing an original socket\n");
close(server_socket); // close an original server socket
return 0;
}
I didnt have this problem before, when I was using nonblocking sockets. So problem is probably connected to them.
If I fill in the blanks to make this into a compilable example (please post an mcve next time)
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <arpa/inet.h>
#define port_number 2222
void error(char const *Msg)
{
perror(Msg);
exit(1);
}
int main()
{
pid_t pid; long long_pid;
int server_socket, new_socket;
struct sockaddr_in server;
bzero((char *) &server, sizeof(server));
server_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if(server_socket < 0) error("ERROR opening socket");
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(port_number);
if(bind(server_socket, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) < 0) error("ERROR on binding");
if(listen(server_socket, 5) < 0) error("Failed to listen for connections.");
while(1)
{
struct sockaddr_in client;
unsigned int client_len = sizeof(struct sockaddr_in);
bzero((char *) &client, client_len);
if((new_socket = accept(server_socket, (struct sockaddr *) &client, &client_len)) < 0)
{
if(errno == EAGAIN) continue;
else error("ERROR on accept");
}
if((pid = fork()) > 0)
{ // this is parent process
close(new_socket);
}
else if(pid == 0)
{ // this is a child process that will handle an incoming request
long_pid = (long) getpid(); // current child's PID
close(server_socket);
server_socket = -1; //closing parent socket
printf("A new connection accepted from blablabla, port %d by process %ld\n", port_number, long_pid);
// ---- doing some staff, running the program
// ---- when Im done:
printf("closing newsock\n");
close(new_socket); // close the new socket
new_socket = -1;
_exit(0);
}
else error("fork() failed");
}
// close the server
printf("closing an original socket\n");
close(server_socket); // close an original server socket
return 0;
}
it seems to work without any issues.
Obviously you're establishing the listening socket with error checks in the parent process and the parent process then isn't doing anything with the listening socket that closes it, so you shouldn't be getting that error from the parent process.
My guess is you're probably mistakenly continuing the loop in the child (in the part you're not showing).
I used "Create-new-thread method" to deal with new clients and met problem in UDP.
First I used main thread to create one TCP thread to deal with new accept()
and create one UDP thread to deal with new recvfrom(). (TCP cases are OK)
Once the first recvfrom() callback, i try to pass the client to the new UDP thread and keep the current one to deal with next new UDP client
It should be work by passing the address and new-created datagram socket to the new thread to continue do recvfrom(), right ?
During experiment, I found that the OLD UDP thread keeps receiving datagram from the client while the new thread just doing while loop and recvfrom() turns to non-blocking manner and returns -1 as a result.
Therefore what is the problem of my code....thanks~
Do I understand something wrongly..?
PassToUDPThread is the typeof struct i made for data passing to new thread:
typedef struct {
sockaddr_in ReceiverSocket;
SOCKET sendSocket;
char* recvbuf;
long packet_size;
}PassToUDPThread;
Here is my code for the FIRST UDP thread function (dealing with first recvfrom() ONLY) :
sockaddr_in *ReceiverSocket = new sockaddr_in;
ReceiverSocket->sin_family = AF_INET;
if (strcmp(recv_hostname, "INADDR_ANY") != 0)
inet_pton(AF_INET, ip_addr_char, &ReceiverSocket->sin_addr.s_addr);
else ReceiverSocket->sin_addr.s_addr = INADDR_ANY;
ReceiverSocket->sin_port = htons((u_short)recv_port);
//*** Create the socket
SOCKET s;
s = socket(AF_INET, SOCK_DGRAM, 0);
printf("Receiver: Socket Created - UDP connection\n");
bind(s, (struct sockaddr *)ReceiverSocket, sizeof(struct sockaddr_in));
do
{
int fromlen = (int)sizeof(struct sockaddr_in);
retVal = recvfrom(s, recvbuf, packet_size, 0, (struct sockaddr*)ReceiverSocket, &fromlen);
std::cout << "UDP recv by MAIN "<<std::endl;
if (retVal == SOCKET_ERROR) {
std::cout << "UDP Socket error : " + WSAGetLastError()<<std::endl;
return 0;
}
else {
SOCKET sendSocket = socket(AF_INET, SOCK_DGRAM, 0);
PassToUDPThread _p;
PassToUDPThread *p = &_p;
p->sendSocket = sendSocket;
p->ReceiverSocket = *ReceiverSocket;
p->recvbuf = recvbuf;
p->packet_size = packet_size;
thrd_t UDPthread;
if (thrd_create(&UDPthread, ThreadUDPReceiver, (void*)p) == thrd_success) {
std::cout<<"success create new UDP thread"<<std::endl;
}
}
} while (retVal>0);
closesocket(s);
UDPReceiver(arg);
return 1;
}
Here is the code for the function on NEW-CREATED UDP thread:
int ThreadUDPReceiver(void *arg) {
int retVal;
SOCKET s = ((PassToUDPThread*)arg)->sendSocket;
char* recvbuf = ((PassToUDPThread*)arg)->recvbuf;
long packet_size = ((PassToUDPThread*)arg)->packet_size;
sockaddr_in *ReceiverSocket = new sockaddr_in;
memcpy(ReceiverSocket, &(((PassToUDPThread*)arg)->ReceiverSocket), sizeof sockaddr_in);
bind(s, (struct sockaddr *)ReceiverSocket, sizeof(struct sockaddr_in));
do {
int fromlen = (int)sizeof(struct sockaddr_in);
retVal = recvfrom(s, recvbuf, packet_size, 0, (struct sockaddr *)ReceiverSocket, &fromlen);
std::cout << "UDP recv by thread "<< std::endl;
} while (true);
return 0;
}
Use a thread pool.
Get rid of the extra UDP sockets. Use the same one to send the response that the request arrived on. Simpler for the client that way too.
I am just learning UDP sockets and this is my first code involving it. I have two programs which send and receive messages back and forth. My question is it seems I have to declare which IP address I am sending/receiving from multiple times throughout the code as it changes but I feel there is a better way to do this without changing the inet_addr manually within the codes. From my reading it looks like sendto and recvfrom may be able to help but I am unsure how to use them in this context. If anyone could show me how to fix my simple problem I would greatly appreciate it! Thanks
CODE 1: Send then Receive
int main(int argc, char *argv[])
{
//initialize socket and structure
int socket_info;
struct sockaddr_in server;
char message[100];
char incoming_message[100];
printf("Input Message: ");
fgets(message, 100, stdin);
//create socket
socket_info = socket(AF_INET, SOCK_DGRAM, 0);
if (socket_info == -1) {
printf("Could not create socket");
}
//assign local values
server.sin_addr.s_addr = inet_addr("172.21.8.178");
server.sin_family = AF_INET;
server.sin_port = htons( 1100 );
//binds connection
if (bind(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("Connection error");
return 1;
}
puts("Bind");
//assign new value to connect to
server.sin_addr.s_addr = inet_addr("172.21.8.179");
//checks connection
if (connect(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("Connection error");
return 1;
}
puts("Connected");
//sends message
if(send(socket_info, message, strlen(message), 0) <0) {
perror("Send failed");
return 1;
}
puts("Message Sent");
//receives message back
if(recv(socket_info, incoming_message, sizeof(incoming_message), 0) <0) {
puts("Received failed");
return 1;
}
puts("Message received");
puts(incoming_message);
close(socket_info);
}
CODE 2: Receive then Send
int main(int argc, char *argv[])
{
//initialize socket and structure
int socket_info;
struct sockaddr_in server;
char incoming_message[100];
//create socket
socket_info = socket(AF_INET, SOCK_DGRAM, 0);
if (socket_info == -1) {
printf("Could not create socket");
}
//assign values
server.sin_addr.s_addr = inet_addr("172.21.8.179");
server.sin_family = AF_INET;
server.sin_port = htons( 1100 );
//checks connection
if (bind(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("Connection error");
return 1;
}
puts("Bind");
//Receive an incoming message
if( recv(socket_info, incoming_message, sizeof(incoming_message), 0) < 0) {
puts("Received failed");
return 1;
}
puts("Message received");
puts(incoming_message);
server.sin_addr.s_addr = inet_addr("172.21.8.178");
if (connect(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("Connection error");
return 1;
}
puts("Connected");
//Sends message back
char message[100];
printf("Input Message: ");
fgets(message, 100, stdin);
if(send(socket_info, message, strlen(message), 0) <0) {
perror("Send failed");
return 1;
}
puts("Message Sent");
close(socket_info);
}
If you use the function recvfrom()
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
What this function does is it fills a structure of sockaddr with the IP and port information of the packet that it has just received. For example, if your code that sends first then receives sends a packet to the receiver, the receiver should be able to fill the structure values of sin_addr and sin_port with the correct values. You can then make a call of sendto() with this information in order to send it to the correct machine.
Here's the man pages for these functions:
https://linux.die.net/man/2/recvfrom
https://linux.die.net/man/2/sendto
Try using this:
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)
127.0.0.1 is the loopback IP. The address is used to establish an IP connection to the same machine, which seems to be your case.
A detailed way to solve the problem can be found here
Here is my code:
void error(const char *msg)
{
perror(msg);
exit(1);
}
void sServer::acceptClientConnections(int listenerSocket)
{
struct sockaddr clientAddress;
socklen_t sizeOfClientAddress = sizeof(clientAddress);
while (true)
{
int newConnection = accept(listenerSocket, &clientAddress, &sizeOfClientAddress);
std::cout << "Someone connected ... " <<std::endl;
liveConnections.push_back(newConnection);
}
}
int sServer::getServerListenerSocket()
{
return serverListenerSocket;
}
sServer::sServer(int port)
{
int serverListenerSocket;
struct sockaddr_in serv_addr;
serverListenerSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverListenerSocket < 0)
error("ERROR opening a socket. Cannot start sever. Exiting ...");
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
std::cout << "Host ip: " << serv_addr.sin_addr.s_addr << "\n";
if ( bind(serverListenerSocket, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 )
error("ERROR on binding server socket. Are you running another instance of this server ?");
listen(serverListenerSocket, 45);
}
Called like this:
int main()
{
sServer superServer(9889);
std::thread handleConnections( &sServer::acceptClientConnections, superServer, superServer.getServerListenerSocket() );
}
I was expecting accept to wait for incoming connections, and when a connection comes in, become active.
But instead, when i run the program, it continuously prints "Someone connected ..." even though no connections are being made.
Ironically, if I start the thread at the end of the constructor, it works well.
Can you please explain why this is happening and what would be the correct way to accept a connection ?
Now that we've determined the error, the problem is the local variable in the constructor:
sServer::sServer(int port)
{
int serverListenerSocket;
Just remove it. It is shadowing the class member of the same name, so the latter is never getting set, so accept() is getting EBADF, returning -1, never displaying an accepted connection, smoking the CPU, etc.
The reason it works when you start the thread inside the constructor is that the local variable is still in scope.
I'm trying to build a client -> proxy server -> server application.
I need help with the proxy server, how do i make it send data to the server right now it can only communicate with the client.
Here is my codef or the proxy server, I modified it from an example. I'm new at this.
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
pid = fork();
if (pid < 0)
error("ERROR on fork");
if (pid == 0) {
close(sockfd);
dostuff(newsockfd);
exit(0);
}
else close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
/******** DOSTUFF() *********************
There is a separate instance of this function
for each connection. It handles all communication
once a connnection has been established.
*****************************************/
void dostuff (int sock)
{
int n, p;
char buffer[256];
char request;
FILE *file;
file = fopen("process.log","a+");
do
{
//here the proxy server receives data from the client
bzero(buffer,256);
p = read(sock,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("num: %s\n",buffer);
//here the proxy servers replies to the client.
n = write(sock,buffer,sizeof(buffer));
//here the process should send data to the server
//...codes i need help with...
if (n < 0) error("ERROR writing to socket");
fprintf(file,"%s\n",buffer); /*writes*/
}while(p != 0); //this runs the process +1 more than it should. wonder why?
fclose(file);
}
DoStuff() .... you can also check the comments I added.
Also how do I send a message to the client as soon as the client is connected to the server, something like a welcome client message? :)
note: the proxy server sends a GET request to a HTTP 1.1 server.
I would really appreciate it. Thanks :)
To connect to the server, you're going to have to call socket and then connect to get that socket connected to your real server from the proxy. See section 5 here:
http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html
Additionally, check p instead of n 4 lines into your do-while loop in DoStuff().