Thread: Stream Server

  1. #1
    Registered User ch4's Avatar
    Join Date
    Jan 2007
    Posts
    154

    Stream Server

    I'm trying to make a stream server.
    This first attempt sends a mp3 file to the media that request http://127.0.0.1:7000/test.mp3
    The only that server does is to read and print the whole request(blue code), send the answer (red code) and finally stream the file(green code).
    Server runs once.

    Here is the list with my problems-questions :
    1) Is something missing from my code ?

    2) Why after the end of server's execution i have to wait a minute(or less) for another one ? I get this error "Address already in use"

    3) Why media-player/browser sometimes open the file and sometimes not. (I mean that, i run server and i request through firefox the file and i get it. The next execution will not work and server won't stream file)

    4) How can i achieve a real streaming because this one just loads the file to media-player/browser and after stores or play it.

    *This is not the final code but as i test network C for first time i want to learn by testing.

    Thanks in advance

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <unistd.h>
    
    #define BACKLOG SOMAXCONN
    #define BUFSIZE 1024
    
    int main(void)
    {
     char buffer[BUFSIZE];
     int socketFd;
     int newSocketFd;
     int port=7000;
    
     int res;
     
     FILE *stream;
    
     struct sockaddr_in server;
     struct sockaddr_in client;
    
     struct hostent *rem;
    
     socklen_t clientLength;
    
    
            //Create socket
            socketFd = socket(PF_INET,SOCK_STREAM,0);
            if (socketFd == -1)
            {
              fprintf(stderr,"Error creating socket : ");
              perror("");
    
              return -1;
            }
    
            //Binding the above socket
            server.sin_family = PF_INET;
            server.sin_addr.s_addr = htonl(INADDR_ANY);
            server.sin_port = htons(port);
    
            res = bind(socketFd,(struct sockaddr *)&server,sizeof(struct sockaddr_in));
            if(res < 0)
            {
              fprintf(stderr,"Error binding socket : ");
              perror("");
    
              close(socketFd);
    
              return -1;
            }
    
            //Listening for connections
            res = listen(socketFd,BACKLOG);
            if(res < 0)
            {
              fprintf(stderr,"Error listening socket : ");
              perror("");
    
              close(socketFd);
    
              return -1;
            }
    
            printf("Server ready to accept clients\n");
    
            clientLength = sizeof(struct sockaddr_in);
            newSocketFd = accept(socketFd, (struct sockaddr *)&client, &clientLength);
            if(newSocketFd < 0)
            {
              fprintf(stderr,"Fail to accept connection : ");
              perror("");
            }
    
            printf("Connection established\n");
    
            recv(newSocketFd,buffer,BUFSIZE,0);  printf("%s",buffer);
    
            send(newSocketFd,"HTTP/1.0 200 OK\r\n",18,1);
            send(newSocketFd,"Sever: musicstreamer v1.0\r\n",28,1);
            send(newSocketFd,"Connection: close\r\n",20,1);
            send(newSocketFd,"Content-Type: audio/mpeg\r\n\r\n",26,1);
    
            stream = fopen("test.mp3","rb");
            while(fread(buffer,1,1,stream) > 0)
              send(newSocketFd,buffer,1,0);
            fclose(stream);
    
            close(newSocketFd);
            close(socketFd);
    
    
    
     return 0;
    }
    Last edited by ch4; 06-09-2009 at 09:33 AM.

  2. #2
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    For starters clear the local variables server and client so they won't contain garbage values, as in
    Code:
    struct sockaddr_in server = {0};
    struct sockaddr_in client = {0};

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by ch4 View Post
    Why after the end of server's execution i have to wait a minute(or less) for another one ? I get this error "Address already in use"
    Make the following change.
    Code:
            //Binding the above socket
            server.sin_family = PF_INET;
            server.sin_addr.s_addr = htonl(INADDR_ANY);
            server.sin_port = htons(port);
    
            int reuse = 1;
            setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
            res = bind(socketFd,(struct sockaddr *)&server,sizeof(struct sockaddr_in));
    (Of course, the declaration of reuse needs to be higher)
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Registered User ch4's Avatar
    Join Date
    Jan 2007
    Posts
    154
    Quote Originally Posted by itCbitC View Post
    For starters clear the local variables server and client so they won't contain garbage values, as in
    Code:
    struct sockaddr_in server = {0};
    struct sockaddr_in client = {0};
    Quote Originally Posted by brewbuck View Post
    Make the following change.
    Code:
            //Binding the above socket
            server.sin_family = PF_INET;
            server.sin_addr.s_addr = htonl(INADDR_ANY);
            server.sin_port = htons(port);
    
            int reuse = 1;
            setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
            res = bind(socketFd,(struct sockaddr *)&server,sizeof(struct sockaddr_in));
    (Of course, the declaration of reuse needs to be higher)
    Thank you, both helped.

    Any ideas for the rest problems ?

  5. #5
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    Why are you sending the HTTP header out-of-band, and the HTTP content in-band? That doesn't seem right.

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by bithub View Post
    Why are you sending the HTTP header out-of-band, and the HTTP content in-band? That doesn't seem right.
    It definitely isn't. HTTP protocol does not use OOB signaling anywhere. In fact, I'm not aware of any widely-used protocol that does.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  7. #7
    Registered User ch4's Avatar
    Join Date
    Jan 2007
    Posts
    154
    Quote Originally Posted by bithub View Post
    Why are you sending the HTTP header out-of-band, and the HTTP content in-band? That doesn't seem right.
    I've already fixed that, but i didn't update it.

    I try to send to the client a m3u list by changing to "Content-Type: audio/x-mpegurl"
    and this one
    Code:
            url_encode("http://127.0.0.1:7000/test.mp3\n",buffer,BUFSIZE,1);
            send(newSocketFd,buffer,strlen(buffer),0);
    and it's working fine.

    Based on something i read, my server sends bytes of mp3 faster than client can read and client may not receive all of them. So i want to re-send the lost bytes, but here is my new problem. Send functions returns the number of bytes sent but is this enough to be sure that all gone well ?

  8. #8
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    but is this enough to be sure that all gone well ?
    Yes. There should not be any "lost" bytes with the TCP protocol.

  9. #9
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    You should be checking the return value from send(), which will tell you how much is sent. Also, change your reading loop so that you're not reading/sending 1 byte at a time. Read a fair chunk out of that file (1K or better), send that, then repeat. Doing single byte read/sends is going to waste an incredible amount of CPU time compared... worst - if during that read, the previous byte actually gets sent, then you're sending 1 byte at a time... which is terrible. Read as much as you can, and send as much as you have available to send. (But try to minimize the amount of data you actually have to send.)
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  10. #10
    Registered User ch4's Avatar
    Join Date
    Jan 2007
    Posts
    154
    Update v1.0 but streaming is still a problem. Would my router be the problem ?
    I run my server on another machine (ubuntu 8.4) and i got "pipe broken" in firefox.

    I also run it using as client wget and it works fine, so i can't see where is the problem.
    Firefox's plugin, totem, my code ????

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    #include "url_codec.h"
    
    #define BACKLOG SOMAXCONN
    #define BUFSIZE 1024
    
    
    int serveClient(void);
    int sendAll(int socket, const void *buffer,int len,int flags);
    
    
    int main(void)
    {
     char buffer[BUFSIZE];
     int socketFd;
     int newSocketFd;
     int port=7000;
    
     int res,reuseAddr;
     
     //FILE *stream;
     int stream;
    
     struct sockaddr_in server = {0};
     struct sockaddr_in client = {0};
    
     struct hostent *rem;
    
     socklen_t clientLength;
    
    
            //Create socket
            socketFd = socket(PF_INET,SOCK_STREAM,0);
            if (socketFd == -1)
            {
              fprintf(stderr,"Error creating socket : ");
              perror("");
    
              return -1;
            }
    
            //Prepare options of socket
            server.sin_family = PF_INET;
            server.sin_addr.s_addr = htonl(INADDR_ANY);
            server.sin_port = htons(port);
            reuseAddr = 1;
    
            setsockopt(socketFd,SOL_SOCKET,SO_REUSEADDR,&reuseAddr,sizeof(int));
    
            //Binding the above socket
            res = bind(socketFd,(struct sockaddr *)&server,sizeof(struct sockaddr_in));
            if(res < 0)
            {
              fprintf(stderr,"Error binding socket : ");
              perror("");
    
              close(socketFd);
    
              return -1;
            }
    
            //Listening for connections
            res = listen(socketFd,BACKLOG);
            if(res < 0)
            {
              fprintf(stderr,"Error listening socket : ");
              perror("");
    
              close(socketFd);
    
              return -1;
            }
    
            printf("Server ready to accept clients\n");
    
            clientLength = sizeof(struct sockaddr_in);
            newSocketFd = accept(socketFd, (struct sockaddr *)&client, &clientLength);
            if(newSocketFd < 0)
            {
              fprintf(stderr,"Fail to accept connection : ");
              perror("");
            }
    
            printf("Connection established\n");
    
            strcpy(buffer,"\0");
            while(strstr(buffer,"\r\n\r\n") == NULL)
            {
              recv(newSocketFd,buffer,5,0);
              printf("%s",buffer);
            }
    
            strcpy(buffer,"\0");
            strcpy(buffer,"HTTP/1.0 200 OK\r\n");                   puts(buffer);
            sendAll(newSocketFd,buffer,strlen(buffer),0);
    
            strcpy(buffer,"Sever: musicstreamer v1.0\r\n");         puts(buffer);
            sendAll(newSocketFd,buffer,strlen(buffer),0);
    
            strcpy(buffer,"Connection: close\r\n");                 puts(buffer);
            sendAll(newSocketFd,buffer,strlen(buffer),0);
    
            strcpy(buffer,"Content-Type: audio/mpeg\r\n\r\n");      puts(buffer);
            sendAll(newSocketFd,buffer,strlen(buffer),0);
    
            stream = open("test.mp3",O_RDONLY);
            if(stream < 0) perror("");
    
            while(read(stream,buffer,1) > 0)
            {
              sendAll(newSocketFd,buffer,1,0);
            }
            close(stream);
    
            close(newSocketFd);
            close(socketFd);
    
    
     return 0;
    }
    
    int sendAll(int socket, const void *buffer,int len,int flags)
    {
     int bytesSent=0;
    
            bytesSent += send(socket,buffer,len,flags);
            while(bytesSent < len)
            {
              bytesSent += send(socket,buffer+bytesSent,len-bytesSent,flags);
            }
    
     return 1;
    }
    I'll fix byte rate later thanks Cactus Hugger

  11. #11
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by ch4 View Post
    Update v1.0 but streaming is still a problem. Would my router be the problem ?
    I run my server on another machine (ubuntu 8.4) and i got "pipe broken" in firefox.
    That happens when one side shuts down the receiving end of their connection, and the other end tries to send() to it. The host which tried to send() to a closed socket gets a SIGPIPE. You can turn that off if you want with various socket options (or are they ioctls? I don't remember).

    In other words, your server closed the connection too early, and the client tried to write something to a closed connection.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  12. #12
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Code:
            strcpy(buffer,"\0");
            while(strstr(buffer,"\r\n\r\n") == NULL)
            {
              recv(newSocketFd,buffer,5,0);
              printf("%s",buffer);
            }
    You have a possible buffer overflow here. If recv() actually does get 5 bytes, they will not be null-terminated, and strstr() is going to read past the end of buffer, unless there is a null. You're probably getting lucky, since in 1024 bytes, there probably is a null, but: add one in.

    Further, say you get "\r\n\r" in one recv(), and "\n" in the next -- you've missed the "\r\n\r\n".

    Finally, don't recv() 5 bytes at a time. recv() as much as you can at a time. recv() BUFSIZE-1, add a null terminator. Look for a "\r\n\r\n", if you see it, we're done. If not, then move the last 3 bytes to the front of the buffer, and repeat. Like so:
    Code:
    // used is a size_t, holding how much of our buffer is in use.
    used = 0;
    while(1)
    {
    	// Go get some data. ret is an int.
    	ret = recv(newSocketFd, buffer + used, BUFSIZE - 1 - used, 0);
    	if(ret < 0)
    	{
    		fprintf(stderr, "Error in recv'ing headers.\n");
    		// Close down sockets...
    		// ...I'm lazy. Don't you be.
    		return 1;
    	}
    	else if(ret == 0)
    	{
    		fprintf(stderr, "Connection closed?\n");
    		// Ditto above comment...
    		return 1;
    	}
    	// Null-terminate the buffer.
    	buffer[ret + used] = 0;
    	used += ret;
    	// Go look for the \r\n\r\n
    	if(strstr(buffer, "\r\n\r\n") != NULL)
    		break;
    	// Didn't find it.
    	if(used > BUFSIZE / 2)
    	{
    		// The buffer is more than half-full. Let's empty it.
    		// The last three characters could be \r\n\r, so keep them around.
    		memcpy(buffer, buffer + used - 3, 3);
    		used = 3;
    	}
    }
    And I'm sitll poking you about sending 1 byte at a time, but I see your note. :-)

    Finally, in sendAll() (good job with that function, btw.), check to make sure send isn't returning an error.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  13. #13
    Registered User ch4's Avatar
    Join Date
    Jan 2007
    Posts
    154
    Solved !!!! It's working

    The problem was my router, so i change the address to access my server, from 127.0.0.1 to 0.0.0.0

    Thanks Cactus, i appreciate your help.

    PS : @Cactus take a look a the red code.
    According to wget with previous code streaming last 12-16 secs, now just 0.3

    Code:
            stream = fopen("test.mp3","rb");
            if(stream == NULL)
            {
              close(newSocketFd);
              perror("");
    
              return -1;
            }
    
            res = stat("test.mp3",&fileInfo);
            if(res < 0)
            {
              fprintf(stderr,"Cannot access file\n");
              perror("");
    
              fclose(stream);
              close(newSocketFd);
              close(socketFd);
    
              return -1;
            }
    
            //Calculate byterate
            byterate = BUFSIZE;
            while(fileInfo.st_size % byterate != 0)
              byterate--;
    
            //Now stream file
            while(fread(buffer,1,byterate,stream) > 0)
            {
              if(sendAll(newSocketFd,buffer,byterate,0) == 0)
              {
                fprintf(stderr,"Fail to transmit file\n");
    
                break;
              }
            }
            fclose(stream);
    
            close(newSocketFd);
            close(socketFd);
    
    
     return 0;
    }
    
    int sendAll(int socket, const void *buffer,int len,int flags)
    {
     int bytesSent;
     int ret_bytes;
    
    
            //Try to sent the package
            ret_bytes = send(socket,buffer,len,flags);
            if(ret_bytes < 0)
              return 0;
    
            //Increase bytes that sent
            bytesSent = ret_bytes;
    
            //Try to resend the whole package (if necessary)
            while(bytesSent < len)
            {
              ret_bytes = send(socket,buffer+bytesSent,len-bytesSent,flags);
              if(ret_bytes < 0)
                return 0;
    
              bytesSent += ret_bytes;
            }
    
    
     return 1;
    }

  14. #14
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    The code in red is ew. If I feed you a large file whose filesize is prime, then it's going to read 1 byte at a time, and performance will suffer. First, lower performance is bad, but lower performance on files whose filesize is prime is just strange.

    You're worrying about a read only partially filling the buffer, judging by your code. This is good, but wrong approach. Just read a nice, round number, such as a multiple of 512 (which BUFSIZE is) as this size is nice for most disk. (But is situation dependent, and won't mean beans if you're reading off a network/memory/compressed file/etc.) Then check the return value from fread(), and send() however many bytes fread() says it read, so that when you get that last chunk of data, it'll handle it.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  15. #15
    Registered User ch4's Avatar
    Join Date
    Jan 2007
    Posts
    154
    Right. I haven't thought about primes.
    Your way is much more faster than mine, so I'll keep yours.

    Thank you one more time.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Server Architecture
    By coder8137 in forum Networking/Device Communication
    Replies: 2
    Last Post: 01-29-2008, 11:21 PM
  2. Where's the EPIPE signal?
    By marc.andrysco in forum Networking/Device Communication
    Replies: 0
    Last Post: 12-23-2006, 08:04 PM
  3. IRC, reading the stream
    By Iyouboushi in forum C# Programming
    Replies: 6
    Last Post: 08-03-2006, 05:34 PM
  4. IE 6 status bar
    By DavidP in forum Tech Board
    Replies: 15
    Last Post: 10-23-2002, 05:31 PM
  5. socket question
    By Unregistered in forum C Programming
    Replies: 3
    Last Post: 07-19-2002, 01:54 PM