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.
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.
Brand new to StackOverflow and definitely brand new to figuring out how to get sockets to work in C. Here's what I'm trying to do: I need to create two programs where one acts as a "daemon" (not actually, you just launch it first and it runs in the background) that listens on a specified port, and then another program that attempts to send information -- via that port -- from a plaintext file, along with the name of a "key" file that should be used to encrypt it. The daemon program connects to the (let's call it client) program, forks off a new process, accepts the information, encrypts the text accordingly, and then sends it back to the client program to be stored in a file.
This last part is where I'm having trouble. I've been able to successfully transfer all of the data from the client to the daemon program, and even successfully encrypt it; I tried storing the info into a temp file to see how it was coming out and everything looked as it should. But when I try to send the information back -- it's worth noting that I'm trying to send it back in chunks as the daemon program is encrypting it and therefore potentially still receiving info -- the client only receives a fraction of the data before the connection is seemingly closed and the process is finished.
Sorry for the lengthy post, just trying to be as detailed as possible. I tried searching for some posts regarding this topic and I did find this one, but it wasn't quite the same issue (plus the suggested fixes were things I already tried). Below is what I think is the pertinent code. This is only my current set up, so certain aspects might just be random bits from different approaches I've tried, e.g. the shutdown on write on the client side is a recent addition that doesn't appear to have made a difference. I've tried a number of different things to make this work over the past week, so if any of the suggestions that come in are things that I've tried, I'll let you folks know. Thanks in advance!
Client:
//Create socket, check for success
//
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1){
fprintf(stderr, "socket creation failed");
exit(1);
}
//Create address structure for socket to connect to
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
int success;
success = connect(sockfd, (struct sockaddr*) &server, sizeof(server));
if(success == -1){
fprintf(stderr, "Could not find port, failed to connect socket\n");
exit(2);
}
//IF all is well, open up the plaintext file for extracting data
FILE* ptextSend = fopen(argv[1], "r");
int totalNeeded;
rewind(ptextSend);
fseek(ptextSend, 0L, SEEK_END);
totalNeeded = ftell(ptextSend);
totalNeeded = totalNeeded - 1;
rewind(ptextSend);
//First, send key path
send(sockfd, keypath, sizeof(keypath), 0);
//Then, send contents of file
int n = 0;
char buffer[1000];
while(n < totalNeeded){
fgets(buffer, 1000, ptextSend);
printf("right now buffer is %s\n", buffer);
n = n + (send(sockfd, buffer, sizeof(buffer), 0));
}
shutdown(sockfd, 1);
//Attempt to receive encrypted info back
n=1;
while(n != 0){
char* newBuff[1000];
n = recv(sockfd, newBuff, sizeof(newBuff) - 1, 0);
if(n!=0)
fprintf(stdout, "this is the client: %s\n", newBuff);
}
Daemon/Server code:
//Create socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1){
fprintf(stderr, "Server error: failure to create socket.\n");
exit(1);
}
//Create address for socket
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
//Bind socket to port using address struct
int bindSuccess = bind(sockfd, (struct sockaddr*) &server, sizeof(server));
if(bindSuccess == -1){
fprintf(stderr, "Server error: bind call failed.\n");
exit(1);
}
//Set socket to listen
int listenSuccess = listen(sockfd, 5);
if(listenSuccess == -1){
fprintf(stderr, "Server error: listen call failed.\n");
exit(1);
}
//Accept next client connection
struct sockaddr_in client_addr;
socklen_t client_length = sizeof(client_addr);
int client_sockfd = accept(sockfd, (struct sockaddr*) &client_addr, &client_length);
if(client_sockfd == -1){
fprintf(stderr, "Server error: accept call failed.\n");
exit(1);
}
pid_t pid = fork();
if(pid < 0){
fprintf(stderr, "Error forking process on connection.\n");
exit(1);
}
if(pid == 0){
//First receive key path
char keybuff[100];
recv(client_sockfd, keybuff, sizeof(keybuff),0);
FILE* theKey = fopen(keybuff, "r");
char buffer[1000];
int n = 1;
while(n != 0){
n = recv(client_sockfd, buffer, sizeof(buffer) - 1, 0);
strtok(buffer, "\n");
char* newString = encrypt(buffer, theKey);
send(client_sockfd, newString, sizeof(newString) - 1, 0);
}
if(n == -1){
fprintf(stderr, "Server error: failed to read from socket.\n");
exit(1);
}
fclose(theKey);
close(client_sockfd);
close(sockfd);
return 0;
}else
return 0;
}
What I should be getting back is "right now buffer is: THE RED GOOSE FLIES AT MIDNIGHT STOP" followed by its encrypted version, so 36 characters of gibberish (occasionally broken up with "this is the client" and a newline). Instead, the total output is:
right now buffer is THE RED GOOSE FLIES AT MIDNIGHT STOP
this is the client: BPZDOSZ
...so just seven characters worth of data and then it exits (successfully).
I am attempting to create a basic server that supports multiple clients. I want the main server to connect to two clients, and then fork off and pass the file descriptors for the clients to another program via a call to execl. Both of the clients connect to the server and are able to communicate with it (tested via asking the clients for user names or handles), but when I attempt to pass the clients to the second program (which is meant to be a personal server between the clients to host a board game match) no output is shown on the client's end when the second program attempts to contact them, I am positive it is the way I am attempting to pass the connection information. Any help with passing the connections correctly is appreciated.
Here is the code for the main server after it accepts two connections:
Main Server: Note. Added additional error checking as recommended.
if(fork() == 0){
close(listener);
int nBytes;
char* playerOne[20];
char* playerTwo[20];
//Creates strings to hold file descriptor information for execl
char connAscii[sizeof(int)];
char connAscii2[sizeof(int)];
snprintf(connAscii,sizeof(conn), "%d", conn);
snprintf(connAscii2,sizeof(conn2), "%d", conn2);
fprintf(stderr, "Int conn: %d, asciiConn: %s, backToInt: %d", conn, connAscii, atoi(connAscii));
char *argf[2];
argf[0] = connAscii;
argf[1] = connAscii2;
//Send Handle Request to Connection 1
nBytes = send(conn, handleRequest, sizeof(handleRequest),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Receive Handle from Connection 1
nBytes = recv(conn, playerOne, 20, 0);
if(nBytes == -1){
perror("recv");
exit(1);
}
//Send Handle Request to Connection 2
nBytes = send(conn2, handleRequest, sizeof(handleRequest),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Receive Handle from Connection 2
nBytes = recv(conn2, playerTwo, 20, 0);
if(nBytes == -1){
perror("recv");
exit(1);
}
//Send Handle for Connection 2 to Connection 1
nBytes = send(conn, playerTwo, sizeof(playerTwo),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Send Handle for Connection 1 to Connection 2
nBytes = send(conn2, playerOne, sizeof(playerOne),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Passes file descriptors to nimMatch
execl("nimMatch", "nimMatch", argf, (char *)0);
}
The personal server(different .c file than main server): Note. Added debuging statements
char greet[] = {"Hello players, please wait for match setup."};
int main(int argc, char *argv[]) {
int conn1 = atoi(argv[1]);
int conn2 = atoi(argv[2]);
int sent;
fprintf(stderr, "Attempting connection\n");
sent = send(conn1, greet,sizeof(greet),0);
if(sent == -1){
perror("send");
exit(1);
}
return 0;
}
And the client code after it has been connected and matched with an opponent:
printf("Your opponent is: %s\n\n Connecting to match server...", otherHandle);
memset(&buf[0],0,sizeof(buf));
if ((numbytes = recv(sockfd, buf, 99, 0)) == -1) { //should come from personal server
perror("recv");
exit(1);
}
printf("From match server: %s\n", buf);
If more code is needed let me know, I know that the clients successfully connect to the server and I get no errors when compiling or running.
The suggested answer from EJP ensures the private server receives the correct input, but the client does not appear to be storing the string from the private server. The adjusted client code below states that the client is receiving 64 bytes but the buf is empty.
printf("You're opponent is: %s\n\n Connecting to match server...", otherHandle);
memset(&buf[0],0,sizeof(buf));
numbytes = recv(sockfd, buf, 99, 0);
if (numbytes == -1) {
perror("recv");
exit(1);
}
if(strlen(buf) < 1)
fprintf(stderr, "No buffer input, found %d bytes\n", numbytes);
printf("From match server: %s\n", buf);
You're passing the arguments to execl() incorrectly. It doesn't take an argument array, it takes a varargs list of arguments. It should be
execl(path, connAscii, connAscii2, (char*)0);
I am attempting to create a client/server system that can handle multiple concurrent connections using the unix system call fork.
The client enters a movie title, and the server will check if the movie was there or not. If it was there, it would tell the client the ranking, the name, and the box records.
looking at my forking implementation, the client asks for user input, however the program just simply goes pass it.
OUTPUT EXAMPLE:
connection made with client 127.0.0.1
PID IS 27270
--> all messages read - connection being closed
CLIENT: Please input an string: PID IS 0
At this line, CLIENT: Please input an string: PID IS 0, the user was suppose to input a string, however the program glances over it. How do I make the program take in the string from the client?
SERVER CODE:
int main()
{
int sock, clientsock, mlen, addrsize, msgct, chc, chct, pid;
struct sockaddr_in addr; //ipv4 address
char ch, buf[80];
/*
* Create a socket.
*/
sock = socket(AF_INET, SOCK_STREAM,0); //create socket (AF_NET shows its ipv4 internet connection, SOCK_STREAM shows its a tcp)
if (sock == -1)
{
perror("opening socket");
exit(-1);
}
//Bind socket to local address
/*
* Bind a name to the socket. Since the server will bind with
* any client, the machine address is zero or INADDR_ANY. The port
* has to be the same as the client uses.
*/
addr.sin_family = AF_INET;
addr.sin_port = htons (32351); //port number for local address
addr.sin_addr.s_addr = htonl (INADDR_ANY); //ip address (you can also hard code it)
if (bind(sock, (struct sockaddr *) &addr, //binding, first parameter : is the socket you created, &addr is the
sizeof (struct sockaddr_in)) == -1) //error checking
{
perror ("on bind");
exit (-1);
} //(at this moment we have binded socket)
/*
* Make the socket available for potential clients.
*/
//if there is connection or not?
if (listen(sock,1) == -1)
{
perror("on listen");
exit(-1);
}
//-------Text File Implementation-----------
FILE *fp;
char data[5][200];
char rank[5][2];
char name[5][255];
char value[5][100];
/* opening file for reading */
fp = fopen("movie.txt", "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
fgets (data[0], 200, fp);
int i = 1;
while(fgets (data[i], 200, fp)!=NULL)
{
/* writing content to stdout */
sscanf(data[i],"%s %[^$] %s",rank[i],name[i],value[i]);
puts(data[i]);
i+=1;
}
//CODE DOES NOT IMPLEMENT AFTER THIS WHILE LOOP
//close the file
fclose(fp);
addrsize = sizeof(struct sockaddr_in);
//THIS WHILE LOOP IS NOT BEING IMPLEMENTED...
while(1)
{
clientsock = accept(sock, (struct sockaddr *) &addr, &addrsize);
if (clientsock == -1)//error checking
{
perror("on accept");
exit(-1);
}
printf("connection made with client ");
printf ("%s\n", inet_ntoa (addr.sin_addr)); //also print client address
/* Create child process */
pid = fork();
if (pid < 0)
{
perror("ERROR on fork");
exit(1);
}
if (pid == 0)
{
/* This is the client process */
close(sock);
bool exist = false;
mlen = recv (clientsock, buf, 80, 0);
if (mlen < 0)
{
perror("ERROR reading from socket");
exit(1);
}
int lenS;
int which;
for(int i = 1; i<5; i++)
{
printf("%s\n\n", name[i]);
char *pch = strstr(name[i],buf);
if(pch != NULL)
{
which = i;
exist = true;
puts("GOOD");
}
else
{
puts("bad");
}
}
if(exist)
{
//SEND TO CLIENT FROM HERE!
printf("%s\n", rank[which]);
printf("%s\n", name[which]);
printf("%s\n", value[which]);
lenS = strlen(name[which]);
send (clientsock, name[which], lenS+1, 0);
}
else
{
//SEND TO CLIENT FROM HERE!!!!
printf("NOT HERE ");
send (clientsock, "NOT HERE", 9, 0);
}
printf("Here is the message: %s\n",buf);
exit(0);
}
else
{
close(clientsock);
printf(" --> all messages read - connection being closed\n");
}
}
}
CLIENT CODE:
int main()
{
int sock, addrsize;
struct sockaddr_in addr;
unsigned int in_address;
char buf[80];
int mlen;
/*
* Open a socket for Internet stream services.
*/
sock = socket(AF_INET, SOCK_STREAM,0); //creating a socket to connect to server, AF_INET : ipv4 internet connection, SOCK_STREAM tcp
if (sock == -1)
{ perror("opening socket");
exit(-1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons (32351); //port number has to be the same as the one from server
in_address = 127 << 24 | 0 << 16 | 0 << 8 | 1; //ip address, local host, since we are running client and server on the same computer, it needs to have the same ip address
addr.sin_addr.s_addr = htonl (in_address);
if (connect (sock, (struct sockaddr *) &addr, //binding
sizeof (struct sockaddr_in)) == -1)
{
perror("on connect");
exit(-1);
}
char word[100];
int len;
printf("CLIENT: Please input an string: ");
scanf("%s", word);
//printf("You entered: %s\n", word);
len = strlen(word);
send (sock, word, len+1, 0);
mlen = recv (sock, buf, 80, 0);
printf ("%s\n\n\n\n\n\n\n", buf);
/*
* Do a shutdown to gracefully terminate by saying - "no more data"
* and then close the socket -- the shutdown is optional in a one way
* communication that is going to terminate, but a good habit to get
* into.
*/
if (shutdown(sock, 1) == -1)
{
perror("on shutdown");
exit(-1);
}
printf ("Client is done\n");
close(sock);
}
You are running the client and server programs on the same machine, with the same controlling terminal. The server master process, its client-service subprocess(es), and the independent client process therefore may all write to that terminal. They run independently and concurrently, so their outputs can be mashed up.
The fact that the PID IS 0 message is emitted after the prompt does not indicate that the client program has skipped accepting input, which indeed, I don't see how it could do. The prompt and the PID message come from different processes.
It would make things clearer to launch the server process and the client process from separate (virtual) terminals, so that their output is not mixed.
I need to write a program to retrieve and process a message through a socket. I have no trouble and understand the process of creating the socket, binding the socket, listening for the incoming connection and then accepting it. I have trouble with receiving the message from the file stream that I have created for the accepted connection. My code is below (I've included pretty much all of it for reference but I think the problem comes after the connection is accepted..):
int sockfd; // the socket file descriptor
int conn_fd; // the accepted connection file descriptor
FILE *conn_fs; // the file stream for the accepted connection
char *conn_buff;
//char conn_buff[LINE_MAX]; // a buffer to store the data received from the accepted connection
int main(int argc, char *argv[]) {
int port = 0;
if ((argc != 2) || (sscanf(argv[1], "%d", &port) != 1)) {
fprintf(stderr, "Usage: %s [PORT]\n", argv[0]);
exit(1);
}
if (port < 1024) {
fprintf(stderr, "Port must be greater than 1024\n");
exit(1);
}
struct sockaddr_in servaddr; // socket address structure (socket in address)
// set all bytes in socket address structure to zero, and fill in the relevant data members
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port); // port is the first argument given in the terminal
// tell the user the servaddr structure has been initialised.
//printf("servaddr structure has been initialised..\n\ncreating socket..\n");
// create the socket using IPv4 (AF_INET) and 2-way comms (SOCK_STREAM)
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { // socket() returns < 0 if an error occurs
printf("error: creating the socket..\nexitting..\n");
exit(EXIT_FAILURE);
}
// tell the user the socket has been created
//printf("socket created..\n\nbinding socket..\n");
// bind the socket to the socket address structure defined above
if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { // bind() returns < 0 if an error occurs
printf("error: binding the socket..\nexitting..\n");
exit(EXIT_FAILURE);
}
// tell the user the socket is "bound"
//printf("socket is now \"bound\"..\n\nmarking the socket as passive..\n");
// set the socket to accept incoming connections (listen)
if (listen(sockfd, SOMAXCONN) < 0) { // listen() returns < 0 if an error occurs
printf("error: marking the socket as a passive socket in the function listen()..\nexitting..\n");
exit(EXIT_FAILURE);
}
// tell the user the socket is listening for incoming connections
printf("socket is now passive (listening)..\n\naccepting incoming connections..\n");
// accept an incoming connection
if (conn_fd = accept(sockfd, NULL, NULL) < 0) { // accept() returns < 0 if an error occurs
printf("error: accepting an incoming connection..\nexitting..\n");
exit(EXIT_FAILURE);
}
// tell the user a connection has been accepted
printf("a connection has been accepted..\n\ncreating a file stream for this connection..\n");
/*
// open a file stream associated with conn_fd
if ((conn_fs = fdopen(conn_fd, "r+")) == NULL) { // fdopen() returns NULL if an error occurs
printf("error: associating a stream to the connections file descriptor in the function fdopen()..\nexitting..\n");
exit(EXIT_FAILURE);
}
// echo out the incoming message
/*while (fgets(conn_buff, LINE_MAX, conn_fd) != NULL) { // fill the conn_buff buffer with data from the file stream conn_fs. returns NULL on error or EOF
//while (read(conn_fd,conn_buff,sizeof(char)*LINE_MAX) > 0) {
printf(conn_buff);printf("OH HAIIIIIIIIIIIIIIIIIIIIIIIIII\n");
} printf("OH HAI\n");*/
size_t len = 100;
ssize_t read;
while ((read = getline(&conn_buff, &len, conn_fs)) != -1) {
printf("Retrieved line of length %zu :\n", read);
printf("%s", conn_buff);
}
free(conn_buff);
// check if there was an error
if (ferror(conn_fs) != 0) { // returns nonzero if the error indicator is set for conn_fs (eg, if fgets() above returned NULL due to an error)
printf("error: an error occurred whilst retrieving data from the stream..\nexitting..\n");
exit(EXIT_FAILURE);
}
// close the file stream associated with conn_fd
if (close((int) conn_fs) != 0) { // close the file stream
printf("error: closing the file stream..\nexitting..\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
When I run the program, it stops inside the while ((read = getline(... loop. If I hit enter to flush the buffer then I get "Retrieved line of length 1 : " from the terminal. I figured out that the program is (for some reason I cannot understand) reading from stdin. It waits for me to type anything and as soon as I flush the buffer (ie hit enter) it sends it all back to me. The only way to close the program is using Ctrl+C. For this reason I think there is a problem with my if ((conn_fs = fdopen(conn_fd, "r+")) == NULL) { statement.
I have tried MANY different ways of reading from the stream (fread(), read(), getline(), fgets(), fgetc()...) and they all had the same effect. Then when I realised the problem must be with how I open the file stream, I tried using fopen() but to no avail.
I'm probably making a stupid mistake but can anyone help me with this please?
The client is never closing the connection.