I wrote a simple TCP client and server program in C language.
It works fine among them but I have a doubt.
What if I wanted to access the TCP server from the web server?
I got the headers from web server and I can't write() back to the web browser. Should the response be in HTTP specifications compulsorily?
I get the following error:
Server Code:
// Server side C program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket; long valread;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("In socket");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("In bind");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("In listen");
exit(EXIT_FAILURE);
}
while(1)
{
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("In accept");
exit(EXIT_FAILURE);
}
valread = read( new_socket , buffer, 1024);
printf("%s\n",buffer );
write(new_socket , hello , strlen(hello));
printf("Hello message sent\n");
}
return 0;
}
Output:
GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Hello message sent
What is the problem? Is browser also expecting HTTP type response from the server? As the server is sending plain text, web browser can't display the contents. Is this the reason for the error displayed in web browser?
What is the problem? Is browser also expecting HTTP type response from the server? As the server is sending plain text, web browser can't display the contents. Is this the reason for the error displayed in web browser?
Yes, the browser expects a HTTP response.
Here a simple HTTP response:
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12
Hello world!
C Code snippet:
const char *hello = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nHello world!";
Parts explained:
HTTP/1.1 specifies the HTTP protocol version.
200 OK is the so called response status. 200 means no error.
List of HTTP status codes (wikipedia)
Content-Type and Content-Length are http headers:
Content-Type refers to the content type (who would've guessed?). text/plain means plaintext. (There is also text/html, image/png etc..)
Content-Length total size of the response in bytes.
Related
I've got a simple C socket server listening at localhost:8080 that continuously reads from the client socket until it encounters quit at the end of the message.
I tested this on Chrome (Android) and Firefox (Android). I sent a POST request as follows:
<form
action="http://localhost:8080"
method="POST" >
<input type="hidden" name="MAX_FILE_SIZE" value="100000"/>
Choose a file to upload: <input name="uploadedfile" type="file"/><br/>
<input type="submit" value="Upload File"/>
</form>
On the server side, I could only see that it recieved the request headers. No file data was recieved.
Req from Chrome:
POST / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 52
Cache-Control: max-age=0
sec-ch-ua: "Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
Origin: http://localhost:5000
DNT: 1
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:5000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,bn;q=0.7
When I added enctype="multipart/form-data" to the above form's attribute though, the full data and file with multiple boundaries was recieved.
Afterwards I tried the following POST with and without multipart:
<form
action="http://localhost:8080"
method="POST" >
<input name="test" value="foobar"/>
<input type="submit" value="Submit"/>
</form>
Results were same, only headers were recieved with urlencoded data. Full data was sent with multipart.
My question is why this is happening, and does the browser expect a response in the first case before it continues sending further data?
My aim is to recieve the POST data at once. Is that not possible?
On a side note, I noticed that after the multipart POST request, the request didn't end with two CR LFs, instead just one.
Edit: Just noticed that when I reload the browser it closes the connection and at that moment the remaining POST data shows up (without any CR LF ending after the POST).
Serve code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
int portno = argc == 2 ? atoi(argv[1]) : 8080;
int srvfd = socket(AF_INET, SOCK_STREAM, 0);
int option = 1;
setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
struct sockaddr_in serv_addr;
memset(&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(portno);
if (bind(srvfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
perror("server: error binding");
exit(1);
}
listen(srvfd, 1000);
printf("server: listening at port %d\n\n", portno);
struct sockaddr_in cli_addr;
socklen_t clilen = sizeof(cli_addr);
int clifd = accept(srvfd, (struct sockaddr*) &cli_addr, &clilen);
while (true) {
char buffer[256];
int n = read(clifd, buffer, 255);
if (n == 0) {
fprintf(stderr, "server: error: connection closed\n");
exit(1);
} else if (n < 0) {
perror("server: error reading from socket");
exit(1);
}
buffer[n] = 0;
printf("%s", buffer);
if (!strncmp(buffer, "quit", 4))
exit(0);
}
return 0;
}
After printing some data, call fflush(stdout); to make sure it is not buffered.
There is not an extra CRLF after the end of the POST data. The server knows the end of the POST data because of the Content-Length header. Because the browser specifies Content-Length: 52 the server knows the POST data is exactly 52 bytes.
I am attempting to make a proxy server, currently want to know why the iPhone I am testing it with sends a CONNECT request, gets the response of "HTTP 200 Connection Established" and usually never responds after that.
(sometimes it will respond instantly with "0" or NULL)
I am not actually connecting to where the iPhone wants to go, but I am sending back a response that indicates the proxy has connected
Terminal Output:
./proxy 9000
At this point I enter my local ip in the iPhone proxy settings
Example output:
REC:
CONNECT clientmetrics.kik.com:443 HTTP/1.1
Host: clientmetrics.kik.com
User-Agent: Kik/14.4.0.11622 CFNetwork/897.15 Darwin/17.5.0
Connection: keep-alive
Proxy-Connection: keep-alive
Sent:
HTTP/1.1 200 Connection Established
REC:
// Typically \0 or a 0, or no recv takes place
Code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netdb.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
if(argc == 2) {
int main(int argc, char* argv[]) {
system("clear");
// Set up socket, family, port, ip address
int serversocket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverinfo;
serverinfo.sin_family = AF_INET;
serverinfo.sin_addr.s_addr = INADDR_ANY;
serverinfo.sin_port = htons(atoi(argv[1]));
// bind server info to socket
if(bind(serversocket, (struct sockaddr*)&serverinfo, sizeof(serverinfo)) == -1) {
printf("failed to bind port to socket, change port\n");
return -1;
}
// accept a connection
listen(serversocket, 1);
int clientsocket = accept(serversocket, NULL, NULL);
// recv and print client message
char buffer[2048];
memset(buffer, 0, sizeof(buffer));
if(recv(clientsocket, buffer, sizeof(buffer), 0) == -1) {
printf("Failed in recv function\n");
} else {
printf("REC\n%s\n", buffer);
}
// send Connection Established
char* sendbuffer = "HTTP/1.1 200 Connection Established";
if(send(clientsocket, sendbuffer, sizeof(sendbuffer), 0) == -1) {
printf("Failed in send function\n");
} else {
printf("Sent:\n%s\n", sendbuffer);
// Recv response from iPhone
memset(buffer, 0, sizeof(buffer));
if(recv(clientsocket, buffer, sizeof(buffer), 0) == -1) {
printf("Failed in recv function\n");
} else {
printf("REC:\n%s\n", buffer);
}
}
} else {
printf("Usage: ./proxy <port>\n");
return 0;
}
}
Was just messing around some more and found that the iPhone will never respond beyond my CONNECT request because the connection must be closed after the proxy responds with HTTP 200 - then the connection can be reestablished and the iphone will continue to send data
I'm trying to make a connection localhost on port 80 and send a simple http get request and simultaneously I run wireshark and look at the headers. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
int main(int argc, char *argv[])
{
int yes = 1;
char buffer[1024];
int newsockfd, portno, recv_length, sockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
ssize_t number;
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = 0;
serv_addr.sin_port = htons(80);
connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
if(send(sockfd,
"GET / HTTP/1.1\r\n
Host: localhost\r\n
Connection: Keep-alive\r\n
Cache-Control: max-age=0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,;q=0.8\r\n
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, sdch\r\n
Accept-Language: en-US,en;q=0.8\r\n\r\n",
strlen("GET / HTTP/1.1\r\n
Host: localhost\r\n
Connection: Keep-alive\r\n
Cache-Control: max-age=0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,;q=0.8\r\n
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, sdch\r\n
Accept-Language: en-US,en;q=0.8\r\n\r\n"),
0) > 0)
{
printf("GET send from %d\n", sockfd);
}
else
{
printf("Problem in send %s\n", strerror(errno));
}
But when I compile it and run it gives me a lot of erros. here is the image of errros. After this error I changed the send function to this send(sockfd, "GET / HTTP/1.1\r\n Host: localhost\r\n\r\n", strlen("GET / HTTP/1.1\r\n Host: localhost\r\n\r\n") Compilation went ok but the wireshark shows me HTTP/1.0 400 BAD REQUEST (text/html) So I have few questions.
1)What is the difference between send functions that I've used? I mean does it really matter if I send GET / HTTP/1.1\r\n Host: localhost\r\n\r\n or GET / HTTP/1.1\r\n
Host: localhost\r\n
Connection: Keep-alive\r\n
Cache-Control: max-age=0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,;q=0.8\r\n
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, sdch\r\n
Accept-Language: en-US,en;q=0.8\r\n\r\n
2)How to configure send function to make correct HTTP GET request?
Hope you can help. Thanks.
You have literal newlines inside your string! You need to close and re-open the quotes on each line. For example:
if(send(sockfd,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: Keep-alive\r\n"
"Cache-Control: max-age=0\r\n"
...
I've written a c socket program in c (cygwin) and I want to send some html code to my browser.
I've written the server and if i run it and type in my browser localhost:8888. My program says it sends the correct amount of bytes but my browser seems to receive nothing.
send code:
#include<stdio.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
int main(int argc , char *argv[])
{
int socket_desc , new_socket , c;
struct sockaddr_in server , client;
char *message;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 1);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (new_socket<0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
char *reply =
"HTTP/1.1 200 OK\r\n<Content-Type: text/html\r\n\r\n<!DOCTYPE html>\r\n<html>\r\n<body>\r\n<h1>My First Heading</h1>\r\n<p>My first paragraph.</p>\r\n</body>\r\n</html>";
int i = send(new_socket,reply,strlen(reply),0);
printf("%d",i);
shutdown(new_socket,2);
return 0;
}
Output program:
bind done
Waiting for incoming connections
Connection accepted
98
Output browser:
Error 103 (net::ERR_CONNECTION_ABORTED): Unknown Error
What is wrong ?
Chances are that, unless there's some more code you aren't showing us, your program isn't generating appropriate HTTP headers on the response. A minimal HTTP response would look like:
HTTP/1.1 200 OK
Content-Type: text/html
Your HTML code goes here
Each line should be terminated by CR+LF (\r\n), and there must be two CR+LF pairs (e.g, \r\n\r\n) between the last header and the start of the body.
Here is an example web server in C that you should take a look at.
It shows how the HTTP protocol, transported via TCP, is used to communicate between the browser and the web server.
In order to send data to a browser your server needs to implement the HTTP protocol. This means waiting for a request from the browser, parsing it and then sending a response containing your data back to the browser.
Take a look at these useful resources about HTTP:
HTTP Made Really Easy
HTTP Protocol Standard
The first one in particular provides very easy to understand information.
Hi I'm building a primitive browser in c which is to do a very simple task. I'm trying to get my client to simply readout the response message from a server that I request from. I'm trying to get a simple response from www.yahoo.com. I have experimented with many different request messages which have all sent successfully. The following request messages are below.
GET http://www.yahoo.com HTTP/1.1\r\n
Host: www.yahoo.com:80\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: en-us,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n
Connection: keep-alive\r\n
and
GET http://www.yahoo.com HTTP/1.1
Host: www.yahoo.com:80
The problem is that I am not recv()-ing any bytes from the server. recv() however does not result in error being -1. Rather the server just doesn't want to respond. Below is my code.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#define MAXDATASIZE 500;
int main(int argc, char *argv[]){
struct addrinfo serverSide,*serverInfo;
int mySock, status;
char buf[501],ipstr[INET6_ADDRSTRLEN];
memset(&serverSide, 0, sizeof serverSide);
serverSide.ai_family = AF_UNSPEC;
serverSide.ai_socktype = SOCK_STREAM;
if(getaddrinfo("www.yahoo.com","80",&serverSide,&serverInfo)==0){
printf("get addr success\n");
}
mySock = socket(serverInfo->ai_family, serverInfo->ai_socktype, serverInfo->ai_protocol);
connect(mySock, serverInfo->ai_addr, serverInfo->ai_addrlen);
char msg[500] = "GET / HTTP/1.1\r\n";
strcat(msg," Host: www.yahoo.com:80\r\n");
printf("%s\n",msg);
if((status = send(mySock,msg,strlen(msg),0))== -1){
printf("request not sent %d\n",status);
perror("\n");
}else{
if((status = recv(mySock, buf, 500, 0))== -1){
printf("recieved byte error");
}else{
printf("%s\n Number of bytes recieved %d\n",buf,status);
}
}
close(mySock);
freeaddrinfo(serverInfo);
return 0;
}
Any help would be great. Thanks!
HTTP protocol requires that 2 carriage returns/newlines are sent to end the HTTP request
I dont see them in your question
There must be two newlines after the header: strcat(msg,"Host: www.yahoo.com:80\r\n\r\n");
recv() returns 0 when remote has closed the socket.
Use proper address family AF_INET instead of AF_UNSPEC.
Also check socket() and connect() return values, e.g. (include errno.h, stdlib.h):
if (mySocket == -1) {
perror("Creating socket failed");
exit(EXIT_FAILURE);
}