I'm writing a Minecraft Classic Server in C using TCP sockets in Winsock and I'm writing the function to perform a 'heartbeat', just an HTTP request which should return a URL to me - no headers or HTML at all.
It sends the data to Minecraft.net (at least it says it does) but it just sits there for a few minutes after that and eventually tells me that it got no data from minecraft.net, ie it reads "HeartBeat: Recieved no data from minecraft.net"
I have the following code so far (excluding WSAStartup etc.):
void HeartBeat()
{
unsigned int clSock;
struct hostent *host;
struct sockaddr_in server_addr;
char buffer[128] = "";
char request[256] = "GET /"; //(I will not show the rest of the request...)
if((clSock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("HeartBeat: Error creating socket\n");
return;
} else {
printf("HeartBeat: Success in creating socket\n");
}
printf("HeartBeat: Resolving hostname 'www.minecraft.net'... ");
if((host = gethostbyname("www.minecraft.net")) == NULL)
{
printf("failed\n");
return;
} else {
printf("success!\n");
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(80);
server_addr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
if (connect(clSock, (SOCKADDR*) &server_addr, sizeof(server_addr)) == SOCKET_ERROR)
{
printf("HeartBeat: Error conneting to www.minecraft.net\n");
return;
} else {
printf("HeartBeat: Connected to www.minecraft.net\n");
}
if (send(clSock, request, sizeof(request), 0) < 0)
{
printf("HeartBeat: Sending data failed.\n");
closesocket(clSock);
return;
} else {
printf("HeartBeat: Success in sending data.\n");
}
if ((recv(clSock, buffer, sizeof(buffer), 0)) == 0)
{
printf("HeartBeat: Received no data from www.minecraft.net\n");
closesocket(clSock);
return;
} else {
printf("HeartBeat: Yay, success! Url is '%s'", buffer);
closesocket(clSock);
return;
}
}
Could someone please point out where I've gone wrong? Thanks a million.
You're not sending an HTTP request.
A (minimal) HTTP request would have to be at least the string:
char request[256] ="GET / HTTP/1.0\r\n\r\n";
Or in the case of HTTP 0.9:
char request[256] ="GET /\r\n\r\n";
You must send just that string, not the whole request buffer containing a lot of 0 bytes, so do:
send(clSock, request, strlen(request), 0)
You are doing just 1 recv() call, that might not read the entire response. You're supposed to read until the connection closes (until recv() returns 0). Or to really follow the HTTP protocol, you need to parse the response, look for a Content-Length header. Read all the headers, then read the number of bytes in the body (if any). To really cope with all the minute details of HTTP, you really need a HTTP library though.
Related
My Server is only able to send one message to the client (HELLO), the client then sends a WORD message and after the server had received the WORD message it's supposed to send a word.
For some reason the server only sends the HELLO message and upon receiving the WORD message it never sends the next message (in this case it's GREEK). I've tried so many different things but it just doesn't seem to work.
Server code (only the relevant parts) ALL CODE IS IN C
while (1) {
if ((newsockfd = accept(sockfd, (struct sockaddr *)&dest, &destlen)) == -1) {
perror("Accept call failed");
exit(-1);
}
if ((childpid = fork()) == 0) {
//close(sockfd);
talk_to_client(newsockfd);
//close(newsockfd);
}
else if (childpid > 0) {
//close(newsockfd);
}
}
}
talk_to_client()
void talk_to_client(int sockfd) {
char message[1024] = "HELLO";
char message2[1024] = "GREEK";
char recieved[1024];
ssize_t n;
//cannot send more than one!!!!!!!!! WHY NOT
write(sockfd, message, sizeof(message));
while (1) {
recv(sockfd, recieved, sizeof(recieved), 0);
if (recieved == "WORD") {
//send initial word
printf("SENDING WORD");
write(sockfd, message2, sizeof(message2));
}
if (recieved == "QUIT") {
//close connection
close(sockfd);
}
}
return;
}
Client code (only relevant parts)
char srv[512];
char cli[512] = "WORD";
// Connects socket to server
rv = connect(sockfd, (struct sockaddr *) servaddr, sizeof(struct sockaddr));
if (rv == -1){
perror("Error connecting to the server");
exit(-1);
}
if(recv(sockfd, srv, sizeof(srv), 0) == -1) {
perror("Client receiving error");
}
printf("Client received: %s\n", srv);
if(send(sockfd, cli, sizeof(cli), 0) == -1){
perror("Error sending message to the server");
exit(-1);
}
printf("Client sending: %s\n", cli);
if(recv(sockfd, srv, sizeof(srv), 0) == -1) {
perror("Client receiving error");
}
printf("Client received: %s\n", srv);
close(sockfd);
I tried many different ways to write to client (write, send, etc..) and I know for a fact it has nothing to do with my connect, bind, socket, listen or accept calls but this is the output I keep getting,
Client received: HELLO
Client sending: WORD
Client received:
char cli[512] = "WORD";
...
if(send(sockfd, cli, sizeof(cli), 0) == -1){
sizeof(cli) is 512 based on the definition of cli. So it will send 512 bytes. strlen(cli)+1 would be more correct, i.e. send the string and the \0 at the end of the string.
recv(sockfd, recieved, sizeof(recieved), 0);
This will thus likely receive these 512 bytes in the server, i.e. WORD\0 followed by many bytes junk. Note that I said "likely" since TCP is not a message based protocol but a byte stream and a single send does not need to match a single recv.
if (recieved == "WORD") {
This does not do a string comparison but compares pointer values. strcmp would be more correct here.
I'm using WinSock2.h to receive data from a TCP socket. Here's the the code for creating the socket and receiving from it:
int Socket_Init(SOCKET * pSocket) {
struct addrinfo lHints;
struct addrinfo *lResult = nullptr;
memset(&lHints, 0, sizeof(lHints));
lHints.ai_family = AF_INET;
lHints.ai_socktype = SOCK_STREAM;
lHints.ai_protocol = IPPROTO_TCP;
if (getaddrinfo(ADDR, PORT_ID, &lHints, &lResult) != 0) {
return -1;
}
*pSocket = socket(lResult->ai_family, lResult->ai_socktype, lResult->ai_protocol);
if (*pSocket == INVALID_SOCKET) {
return -2;
}
// Set receive timeout.
uint32_t timeout = 10000;
if (setsockopt(*pSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) == SOCKET_ERROR) {
return -3;
}
// Set send timeout.
if (setsockopt(*pSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) == SOCKET_ERROR) {
return -4;
}
if (connect(*pSocket, lResult->ai_addr, (int)lResult->ai_addrlen) == SOCKET_ERROR) {
return -5;
}
return 0;
}
int Socket_Receive(char * buf, int len, SOCKET * pSocket) {
if (*pSocket == INVALID_SOCKET) {
return -1;
}
int nBytesReceived = recv(*pSocket, buf, len, MSG_WAITALL);
if (nBytesReceived == 0) {
return -2;
} else if (nBytesReceived == SOCKET_ERROR) {
if (WSAECONNABORTED == LAST_ERROR || WSAECONNRESET == LAST_ERROR) {
return -3;
} else {
return -4;
}
}
return nBytesReceived;
}
I use this code to receive packets of 131130 bytes. Using Wireshark, I can see that the incomplete packet happens when there is a retransmission on the last or second-to-last segmented packet (the stack splits the message into chunks of 1460 bytes + header). When this happens, recv() returns (131130 - size retransmitted) instead of 131130. If I do another read for the number of bytes missing, I can get them without problem.
My confusion comes from the fact that I'm using the MSG_WAITALL flag, which doesn't seem to work fully. From the documentation, recv() with the MSG_WAITALL flag will return only if:
The buffer supplied by the caller is completely full.
The connection has been closed.
The request has been canceled or an error occurred.
But I receive no error, the connection is still open, and the buffer isn't full.
I saw this thread, where the replyer says that MSG_WAITALL is not supported by TCP sockets and to use 0 instead of MSG_WAITALL. I tried it, but this resulted in even more retries from my code. Moreover, if it was not supported, then I believe the recv() function should fail immediately with WSAEOPNOTSUPP, which it doesn't.
Am I missing something?
I am writing a program which is supposed to act as a simple proxy between a web server and a browser. The browser connects to my proxy program and my program connects to the web server. My proxy program should simply forward all data it receives from the browser to the web server and vice-versa, without modifying the data in any way and without performing any caching.
I have managed to get a reply from a web server but how would I direct that reply to my browser? Also is there any way to put this into some sort of infinite loop where I can recv and send at will?
Edit:
I've almost got it. I just need to know how to continuously read the sockets. The program closes unexpectedly after I get the Http redirect.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#define SERVER_PORT 8080
#define SA struct sockaddr
#define MAX 80
pthread_t ptid, ptidd;
#define TRUE 1
#define FALSE 0
struct sockets_struct {
int server_sd;
int client_sd;
int new_sd;
}socks;
// Function designed to act as client.
void *client_func(void *sockets)
{
char buffer[MAX];
struct sockaddr_in servaddrr;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
int i, len, rc, on = 1;
//bzero(&servaddrr, sizeof(servaddrr));
// assign IP, PORT
servaddrr.sin_family = AF_INET;
servaddrr.sin_addr.s_addr = inet_addr("192.168.0.1");
servaddrr.sin_port = htons(80);
// connect the client socket to server socket
if (connect(socks->client_sd, (SA*)&servaddrr, sizeof(servaddrr)) != 0) {
printf(" client: connection with the server failed...\n");
exit(0);
}
else
printf(" client: connected to the remote server..\n");
do {
rc = recv(socks->client_sd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" client: recv() failed\n");
}
break;
}
if (rc == 0) {
printf(" client: Connection closed\n");
break;
}
len = rc;
printf(" client: %d bytes received\n", len);
rc = send(socks->new_sd, buffer, len, 0);
if (rc < 0) {
perror(" client: send() failed");
break;
}
} while(TRUE);
}
// Function designed to act as server.
void *server_func(void *sockets)
{
int len, rc, on = 1;
int desc_ready, end_server = FALSE, compress_array = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in6 addr;
int timeout;
struct pollfd fds[200];
int nfds = 1, current_size = 0, i, j;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
rc = setsockopt(socks->server_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0) {
perror(" server: setsockopt() failed\n");
close(socks->server_sd);
exit(-1);
}
rc = ioctl(socks->server_sd, FIONBIO, (char *)&on);
if (rc < 0) {
perror(" server: ioctl() failed\n");
close(socks->server_sd);
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET;
memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(SERVER_PORT);
rc = bind(socks->server_sd, (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0) {
perror(" server: bind() failed");
close(socks->server_sd);
exit(-1);
}
rc = listen(socks->server_sd, 32);
if (rc < 0) {
perror(" server: listen() failed");
close(socks->server_sd);
exit(-1);
}
memset(fds, 0 , sizeof(fds));
fds[0].fd = socks->server_sd;
fds[0].events = POLLIN;
timeout = (3 * 60 * 1000);
do {
printf(" server: waiting on poll()...\n");
rc = poll(fds, nfds, timeout);
if (rc < 0) {
perror(" server: poll() failed\n");
break;
}
if (rc == 0) {
printf(" server: poll() timed out. End program.\n");
break;
}
current_size = nfds;
for (i = 0; i < current_size; i++) {
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN) {
printf(" server: Error! revents = %d\n", fds[i].revents);
end_server = TRUE;
break;
}
if (fds[i].fd == socks->server_sd) {
printf(" server: Listening socket is readable\n");
socks->new_sd = accept(socks->server_sd, NULL, NULL);
if (socks->new_sd < 0) {
if (errno != EWOULDBLOCK) {
perror(" server: accept() failed\n");
end_server = TRUE;
}
break;
}
printf(" server: new incoming connection - %d\n", socks->new_sd);
fds[nfds].fd = socks->new_sd;
fds[nfds].events = POLLIN;
nfds++;
}
else {
printf(" server: Descriptor %d is readable\n", fds[i].fd);
close_conn = FALSE;
do {
rc = recv(fds[i].fd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
if (rc == 0) {
printf(" server: Connection closed\n");
close_conn = TRUE;
break;
}
len = rc;
printf(" server: %d bytes received \n", len);
rc = send(socks->client_sd, buffer, len, 0);
if (rc < 0) {
perror(" server: send() failed\n");
close_conn = TRUE;
break;
}
} while(TRUE);
if (close_conn) {
close(fds[i].fd);
fds[i].fd = -1;
compress_array = TRUE;
}
} /* End of existing connection is readable */
} /* End of loop through pollable descriptors */
} while (end_server == FALSE); /* End of serving running. */
}
int main (int argc, char *argv[])
{
socks.server_sd = socket(AF_INET, SOCK_STREAM, 0);
socks.client_sd = socket(AF_INET, SOCK_STREAM, 0);
if (socks.server_sd == -1) {
printf("socket \"server_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"server_sd\" successfully created..\n");
if (socks.client_sd == -1) {
printf("socket \"client_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"client_sd\" successfully created..\n");
pthread_create(&ptidd, NULL, &client_func, &socks);
pthread_create(&ptid, NULL, &server_func, &socks);
pthread_join(ptidd, NULL);
return 0;
}
You can either write a proxy that understands the data it's proxying or one that doesn't. Your question suggests that you want to write one that doesn't. That is definitely the easier approach.
So once all the connections are setup, you have two things to do. You need to read data from one connection and send it to the other. You also need to read data from the other connection and send it to the first one.
Using two threads is an easy way to do this. You can also fork a process for each direction. But the first way that everyone learns is a select or poll loop. You can punch "select loop proxy" into your favorite search engine to find lots of examples.
NOTE: This answer was written at a time before the OP edited the question and added threads to the code in the question.
The main problem I see with your algorithm is that you seem to assume that you will always receive all data from the client and server in one recv or read call. This cannot be relied upon, even if the web client (browser) only sends a single HTTP request (which is very unlikely, even if only one web page gets loaded).
I suggest you use the following algorithm instead:
Wait for web client (browser) to establish connection to your program.
Create a new socket which connects to web server.
Wait for web server connection to be established. This step is not necessary with your program, as you are using a blocking connect call. It is only necessary if non-blocking or asynchronous sockets are used.
Wait for new data to be available to be read on either of the two sockets, for example by using the function select. When this function returns, it will indicate on which sockets a non-blocking call to recv is possible.
Read from the socket(s) that select reports as having data available to be read, and write this data to the other socket using the send function.
Go to step 4.
However, this algorithm has one possible problem: It assumes that send will always be successful at writing all the bytes immediately, without blocking. Depending on the circumstances (for example the operating system's buffering of sockets) this may not always be the case. It may only be able to partially send the contents of the buffer at once. The documentation of the function send does not specify what will happen if the buffer of the send function is too large to be sent at once, i.e. whether it will block until all the data is sent or whether it will return as soon as it was able to perform a partial send.
Therefore, your algorithm should be able to deal with the case that the data is only partially sent, for example by also checking in step 4 whether it is possible to write more data if not all data was written in a previous call to send.
Also, beware that while your program is blocking on a send call, it will not process any communication in the other direction. For example, while your program is blocking on a send call while forwarding data from the client to the server, it will be unable to forward any data from the server to the client. I don't think that this can cause trouble with the HTTP protocol, because the client and server never send data simultaneously, as the server always waits for the client to finish its request and the client then waits for the server to finish its reply, before it sends another request. However, this may be an issue with other protocols. In particular, if you block communication completely in one direction, this may cause the client or server to get stuck on a blocking send or recv call, too. This could cause a deadlock in all three programs.
Therefore, you may want to consider using non-blocking sockets or asynchronous sockets instead, so that you can continue forwarding network traffic in both directions at all times.
Alternatively, you could continue using blocking socket calls and create two threads, one for forwarding data from the client to the server and one for forwarding data from the server to the client. That way, communication will never be blocked in any direction. But I would recommend using non-blocking sockets or asynchronous socket instead, as threads can get messy.
One thing your algorithm should also do is handle an orderly socket shutdown (indicated by recv returning 0) and error conditions. How to do this depends on what kind of sockets you are using, i.e. whether they are blocking, non-blocking or asynchronous.
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 make server in c by socket. Client send request to server. Server parse it and send back data (html,png,jpg or bash script output). I have some questions about it.
When I read html file and send it to client. If file is large data are not send and browser reset connection The connection was reset How can i wait until all data are send? in this loop.
while ((ret = read(html, buff, 1023)) > 0)
{
write(client_socketfd, buff, ret);
}
Is it possible to send image(png or jpg) same way like html, only change Content type in html header?
How it works if in html file are a tags with src="another.html" after click on it client send GET request?
How it works if in html file are img tags?
Last question what is the best way to close infinity loop server. In linux if I close it with CTRL C socket are not close.
If something else is wrong I will be grateful for your advice.
int main(int argc, char *argv[])
{
int result;
int socket_desc, client_socketfd, c, read_size, buffer = 0;
struct sockaddr_in server, client;
char sprava[256];
int arg;
int port = 0;
char *homeDir = NULL;
//get command line arguments -p port -d home dir
while ((arg = getopt(argc, argv, "p:d:")) != -1) {
switch (arg) {
case 'p':
port = atoi(optarg);
break;
case 'd':
homeDir = optarg;
break;
default:
fprintf(stderr, "Please speicify -p port and -d home directiory\n");
exit(1);
}
}
if (port < 1500 || homeDir == NULL) {
fprintf(stderr, "BAD arguments use: -p port(greather then 1500) -d home dir\n");
exit(1);
}
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
printf("Could not create socket");
return 1;
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
//Bind
if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0)
{
fprintf(stderr, "bind failed\n");
exit(1);
}
printf("bind done\n");
//Listen max 3
listen(socket_desc, 3);
//Accept and incoming connection
int loop = 1;
while (loop) {
printf("Waiting for incoming connections...\n");
c = sizeof(struct sockaddr_in);
loop = 0; //only for testing, if everything run ok loop will be infinity
client_socketfd = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_socketfd < 0) {
fprintf(stderr, "Accept failed\n");
exit(1);
}
//In child proc we are sending data
if (fork() == 0) {
close(socket_desc);//we dont need desc in child
bzero(sprava, 256);//all on '\0'
result = read(client_socketfd, sprava, 255);
printf("Server read: %s\n", sprava);
char* path;
int kod = parser(sprava, &path);//in path is path to file
if (kod == ERROR_FILE_TYPE)
{
printf("BAD request!!!!\n");
shutdown(client_socketfd, SHUT_RDWR);
close(client_socketfd);
}
if (kod == HTML || kod == BASH || kod == JPG || kod == PNG)
{
if (kod == BASH)
{
FILE *pipe;
char *cmd = path;
strcat(cmd, " 2>&1");//error output send to pipe
printf("New command is=%s\n", cmd + 1);//we dont need first /
//open pipe without first /
pipe = popen(cmd + 1, "r");
if (pipe != NULL) {
char text[1035];
while (fgets(text, sizeof(text) - 1, pipe) != NULL) {
printf("output=%s", path);
write(client_socketfd, text, strlen(text));
}
}
pclose(pipe);
}
else if (kod == HTML)
{
int html;
long len;
char buff[1024] = { 0 };
int ret;
printf("Try to open file=%s\n", path + 1);
html = open(path + 1, O_RDONLY);
if (html == -1) {
fprintf(stderr, "Error opening file\n");
}
len = (long)lseek(html, (off_t)0, SEEK_END);//len of file
lseek(html, (off_t)0, SEEK_SET);
sprintf(buff, "HTTP/1.1 200 OK\nServer: nweb/%d.0\nContent-Length: %ld\nConnection: close\nContent-Type: %s\n\n", 20, len, "text/html");
//send html header to client
printf("Length of file=%d\n", len);
write(client_socketfd, buff, strlen(buff));
printf("Header was send\n");
while ((ret = read(html, buff, 1023)) > 0)
{
printf("number of bytes read=%d\n", ret);
//write data to client,it will make connection reset
write(client_socketfd, buff, ret);
}
}
free(path);
}
shutdown(client_socketfd, SHUT_RDWR);
close(client_socketfd);
exit(0);
}
//in parent close client
else {
close(client_socketfd);
wait(&wt);//this wait is only for testing
}
}
close(socket_desc);
return 0;
}
When I read html file and send it to client. If file is large data are
not send and browser reset connection The connection was reset How
can i wait until all data are send? in this loop.
While the loop you refer to has potential problems, there is likely not the answer to your question.
I could reproduce the issue with your code, and after some searching hit on the highly interesting post The ultimate SO_LINGER page, or: why is my tcp not reliable. The key part is this sentence from section 4.2.2.13 of RFC 1122:
If such a host issues a CLOSE call while received data is still
pending in TCP, or if new data is received after CLOSE is called, its
TCP SHOULD send a RST to show that data was lost.
Your program may (and in my tests, does) indeed have received data pending, because at the start of the conversation it calls read(client_socketfd, sprava, 255), thus, if the HTTP GET request is longer than 255 bytes, leaving part of the request pending to be read. Now at the end after all send data has been submitted to the OS by write, when close is called, the pending data is still there, and therefore the OS, by sending the mandated RST, aborts the connection immediately, possibly discarding any not yet transmitted send data in its buffers. So, we have the surprising situation that an omission to receive in the beginning leads to loss of transmit data in the end.
A quick and dirty fix would be to increase the size of sprava and the number of bytes to read so that the whole request is read - but what might be the maximum length of a request? The correct way is to read in a loop until the request is terminated by an empty line consisting of only \r\n.