I'm following a tutorial for creating an HTTP server with sockets using C. I'm on Windows using the gcc compiler. The server runs and I can even hit it and get data back when using a custom client built from C sockets. But When I try run the command
"curl -o - http://127.0.0.1:8001"
to connect to my server, I receive the error:
curl : Unable to read data from the transport connection: An existing connection was forcibly closed by the remote
host.
My server output shows the connection is trying to be made, but doesn't show any errors. Here is my code..
http_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
int main()
{
//open a file to server
FILE *html_data;
html_data = fopen("index.html", "r");
char response_data[1024];
fgets(response_data, 1024, html_data);
char http_header[2048] = "HTTP/1.1 200 OK\r\n\r\n";
strcat(http_header, response_data);
//create a socket
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM,0);
// specify an address for the socket
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8001);
server_address.sin_addr.s_addr = INADDR_ANY;
//bind the socket to our specified IP and port
bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address));
listen(server_socket,5);
int client_socket;
while(1) {
client_socket = accept(server_socket, NULL, NULL);
printf("client socket response: %d\n", client_socket);
perror("socket");
send(client_socket, http_header, sizeof(http_header),0);
close(client_socket);
}
return 0;
}
index.html
<html><body>welcome to the HTTP Server!</body></html>
I think you're pretty close to getting it working. The reason curl is complaining is because it's expecting you to have supplied a Content-Length header. You can do this by updating your existing code as follows:
char response_data[1024];
fgets(response_data, 1024, html_data);
size_t message_length = strlen(response_data);
char http_header[2048];
snprintf(http_header, sizeof(http_header), "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n", message_length);
strcat(http_header, response_data);
You also need to update your send code to only send the length of the response string.
send(client_socket, http_header, strlen(http_header),0);
You still have some issues with your error checking as mentioned in the comments, but at least with these changes curl should be happy.
While what I mentioned above is the minimal headers that will satisfy curl, there are others that you need to add to make you code conform to Hypertext Transfer Protocol -- HTTP/1.1
Connection: close
Content-Type: text/html
Related
I suspect this has an easy solution I'm overlooking, probably to do with the client or how this is set up.
Anyways, I'm trying to set up a simple Echo server/client to understand the basics of socket programming. I have a virtual machine running Linux Mint, and the host is running Windows 10. The virtual machine I am setting to run the server c code, and the Windows will be running the client.
I started off making the server code
//Echo Server for UNIX: Using socket programming in C, a client sends a string
//to this server, and the server responds with the same string sent back to the client
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int main()
{
char stringBuffer[50]; //string buffer for reading incoming and resending
int listener, communicator, c; //store values returned by socket system call
if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) //creates a new socket
puts("Could not create socket");
puts("Socket Created");
struct sockaddr_in servAddr, client; //structure from <netinet/in.h> for address of server
servAddr.sin_family = AF_INET; //addressing scheme set to IP
servAddr.sin_port = htons(8888); //server listens to port 5000
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //symbolic constant of server IP address
//binds the socket to the address of the current host and port# the server will run on
if (bind(listener, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
puts("Bind failed");
return 1;
}
puts("Bind Successful");
listen(listener, 5); //listens for up to 5 connections at a time
c = sizeof(struct sockaddr_in);
if ((communicator = accept(listener, (struct sockaddr*)&client, (socklen_t*)&c ))<0)
puts("accept failed");
puts("Connection Accepted");
//wait until someone wants to connect, then whatever is sent can be read from communicator, which can then be sent back
while(1){
bzero(stringBuffer, 50); //sets buffer to 0
read(communicator, stringBuffer, 50); //reads from communicator into buffer
write(communicator, stringBuffer, strlen(stringBuffer)+1); //returns back
}
return 0;
}
after that I tested it out by opening another terminal in the guest machine and typed "telnet localhost 8888" and input whatever strings I wanted.
This test worked so now, onto my Windows machine to create the client side of the socket programming:
#include <winsock.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc, char *argv[])
{
WSADATA wsadata; //variable for using sockets in windows
SOCKET sock; //socket variable for network commands
char sendString[50], recieveString[50]; //variables for sending and recieving messages to/from server
//check if WSA initialises correctly
if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
printf("Error Code: %d", WSAGetLastError());
//creates new socket and saves into sock
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
printf("Could not create socket: %d", WSAGetLastError());
printf("Socket created\n");
struct sockaddr_in servAddr;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //sets the IP address to the same machine as the server
servAddr.sin_family = AF_INET; //addressing scheme set to TCP/IP
servAddr.sin_port = htons(8888); //server address is on port 8888
//connects to device with specifications from servAddr
if (connect(sock, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
printf("Connection Error %d\n", WSAGetLastError());
return 1;
}
printf("Connection Accepted\n");
while(1){
fgets(sendString, 50, stdin); //uses stdin to get input to put into sendString
//sends sendString to server using sock's properties
if (send(sock, sendString, strlen(sendString) + 1, 0) < 0); {
printf("Send Failed");
return 0;
}
//reads from server into recieveString
if ((recv(sock, recieveString, 50, 0)) == SOCKET_ERROR)
printf("Recieve Failed");
printf("%s", recieveString); //prints out recieveString
}
}
Now, with the server still running, when I try out the client-side, I get the response "Connection Error" (from line 35). Having looked at both Unix and WinSock examples, I'm unsure as to why I would be failing the connection. I suspect it might have something to do with a windows to linux VM but I'm not sure.
---UPDATE---
Having updated the accidental semicolon and added the WSAGetLastError, it's showing an error code of 10061; This translates to
"Connection refused.
No connection could be made because the target computer actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running."
[after the 3rd edit:]
Sry, just re-read your question. The important thing is here:
The virtual machine I am setting to run the server c code, and the Windows will be running the client.
127.0.0.1 is an address always only local to an IP enabled box. So you your server is listening on the interface 127.0.0.1 local to the Linux VM and the client tries to connect to 127.0.0.0 local to the Windows box. Those two interfaces are not the same. The result is the obvious, namely the client does not find anything to connect to.
127.0.0.1 (the so called "IPv4 local loopback interface") can only be used for connections local to exactly one box.
if (connect(sock, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0); {
printf("Connection Error");
return 1;
}
This is just a trivial syntax mistake. You are entering the block unconditionally. Remove the first semicolon.
However there is a much more important point to be made. When you get an error from a system call such as connect(), you must print the error. Not just some message of your own devising. Otherwise you don't know whether you simply have a bug, or a temporary problem, or a long-lasting problem, or a permanent problem.
Change the printf() to:
printf("Connect error %s\n", WSAGetLastError());
and then don't continue as though the error didn't happen.
Note that this applies to all system calls, specifically including socket(), bind(), listen(), connect(), accept(), recv(), send(), and friends.
I am trying to send an array of objects to my C++ client using the code below. I originally was trying to do so with just the http library alone in which i further investigated and found this out to be not correct approach.
What i'm not clear with this is how socket.write("hello C++ client") will allow me to send this string and have it appear in my terminal C++ but using socket.emit("arrayTransfer", arrayOfObjects); or a similar variation of what i'm trying below will not allow me to receive anything, I have tried different variations of sending the array of objects but have not succeeded can someone help me understand what exactly may be going on in this code and how Nodejs handles these types of sockets?
thank you.
Here is my questions I asked before to gain a better understanding perhaps.
NodeJs server and C++ client
var server = require("net").createServer();
var io = require("socket.io")(server);
socket.emit("message", myArray[0].name);
};
io.on("connection", handleClient);
server.listen(8080);
C++ CLIENT CODE BELOW
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define LENGTH (512)
#include <errno.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#define PORT_NUMBER (8080) // port number where to port in application
int clientSocket;
char buffer[LENGTH];
struct sockaddr_in serverAddr;
socklen_t addr_size;
int main()
{
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(PORT_NUMBER);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Connect the socket to the server using the address struct ----*/
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
/*---- Read the message from the server into the buffer ----*/
recv(clientSocket, buffer, 1024, 0);
printf("This is your message %s", buffer);
close(clientSocket);
return 0;
}
I'm writing a very small C UDP client. I know that a random port is chosen as source port when you send data to the server. I also know that you can use bind to specify yourself the port you want a response.
However, I don't know when is the port randomly chosen? For example, I would like to rely on the sender address to keep track of users. It currently works only if the client does not shutdown, the port is still the same then a simple memcmp is enough to detect the same client.
This small code will use the same source port until it exits:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
int main(void)
{
int s, error, ch;
struct addrinfo hints, *res;
memset(&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
if ((error = getaddrinfo("localhost", "9988", &hints, &res)))
errx(1, "%s", gai_strerror(error));
if ((s = socket(res->ai_family, res->ai_socktype, 0)) < 0)
err(1, "socket");
while ((ch = fgetc(stdin)) != EOF)
sendto(s, &ch, 1, 0, res->ai_addr, res->ai_addrlen);
}
And running something like : dmesg | ./client will use the same address until the program exits. However, when you run it again, the port is different.
So is it the socket function that choose a port? Or the system? Is it sure that the port will still be the same during the client lifetime?
If the socket is not explicitly bound, then the OS will bind it (with a random port) when you send the first packet. This binding will be active as long as the socket is open, once it's closed the socket is (of course) unbound.
And due to the connectionless nature of UDP sockets, the "server" (if done correctly) should not keep the address of all "clients" that send to it indefinitely. Instead it should use the source address as received in the recvfrom call, and use that for a reply. The only reason to store the source address for more than just a simple request/response, is if you have a more advanced protocol on top of UDP with your own "connection" handling.
Following code is TCP server program just send back “HELLO!!” to client.
When I run server with port 80, bind() is returned Permission denied.
Port 12345 is OK.
How can I use port 80 for this server program?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int
main(){
int sock0;
struct sockaddr_in addr;
struct sockaddr_in client;
int len;
int sock;
char *message;
message = "HELLO !!";
sock0 = socket(AF_INET,SOCK_STREAM,0);
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
inet_pton(AF_INET,"127.0.0.1",&addr,sizeof(addr));
bind(sock0,(struct sockaddr *)&addr,sizeof(addr));
perror("bind");
len = sizeof(client);
sock = accept(sock0,(struct sockaddr *)&client,&len);
perror("accept");
write(sock,message,sizeof(message));
perror("write");
close(sock);
return 0;
}
Ports below 1024 are considered "privileged" and can only be bound to with an equally privileged user (read: root).
Anything above and including 1024 is "free to use" by anyone.
OT: you may know this already, but the port in your example is that for HTTP web servers. Anything listening to this port should speak HTTP, too. A simple "hello world" does not suffice. ;-)
Only the root user is allowed to bind to ports <= 1024. Every ports > 1024 can be bound to by normal users.
Try executing your program as root or with sudo.
you have to run your application with super user account (root)
Run your application with sudo command
I'm working on a real time project on my Debian Wheezy (with real-time patch), it needs a strong reactivity using TCP communication protocol.
When I send a request, the response time is too long (220us) and I don't understand why.
My problem is when I send a request, my application server answers too late for my needs.
So, I decided to write a short program using TCP socket to acquire my server's response time. (see code below)
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
int main(int argc, char* argv[])
{
char sendBuffer [] = "OK";
char buffer [10];
int socket1;
int workingSocket;
socklen_t len;
int nodelay = 1;
struct sockaddr_in sa1;
struct sockaddr sa2;
socket1 = 0;
workingSocket = 0;
len = sizeof(sa1);
memset(&sa1, 0, len);
sa1.sin_addr.s_addr = htonl (INADDR_ANY);
sa1.sin_family = AF_INET;
sa1.sin_port = htons(12345);
socket1 = socket(AF_INET, SOCK_STREAM, 0);
bind(socket1, (struct sockaddr *)&sa1, len);
listen(socket1, 10);
workingSocket = accept(socket1, &sa2, &len);
setsockopt (workingSocket, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay));
// receive and send message back
while (1)
{
recv(workingSocket, buffer, 5, MSG_WAITALL);
send(workingSocket, sendBuffer, 2, 0);
}
}
I check the response time doing the following procedure :
start a wireshark session to trace the network traffic
launch my C server.
send a TCP request for example : $echo 'abcde'|netcat 192.168.0.1 12345
I got a response time of around 200 µs between the moment the string is sent (abcde) and the moment when I receive the reponse on the socket (OK)
This time seems to be very high. I made the same experience on VxWorks and got a response time aproaching 10µs.
Is the Linux kernel really slow or is there a trick to increase the reactivity of the system ?
Thank you for your help and your advices.