LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-10-2009, 05:56 AM   #1
vigneshinbox
LQ Newbie
 
Registered: Mar 2009
Posts: 19

Rep: Reputation: 0
Problem with Socket program..


I wrote a program which will send a message to multiple clients(i.e, broadcasting) that are connected to a server.Once when the client receives a message from the server ,the client should read a file in the server and display it in the client.The client which responds (i.e, client wants all the data stored in a file from the server )first will be served by the server(i.e,)the server should read the file stored in the server itself and send the information in the file to the client and should stop receiving the further request from other clients.
I wrote the coding for that..But its not working properly.Can somebody plz clear the bug and make my program to work in the way i wanted??

server:
Code:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>

int main()
{
        char buf[20]="Hai";
        char buffer[20];
        int conarr[20],con=0,i,r,count,new_fd,sockfd;
        socklen_t sin_size;
        struct sockaddr_storage their_addr;
        unsigned int sock,connect,len,child_pid,sd;
        struct sockaddr_in servaddr,cliaddr;
        sock=socket(AF_INET,SOCK_STREAM,0);
        sd = socket(AF_INET,SOCK_STREAM,0);
        servaddr.sin_family=AF_INET;
        servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        servaddr.sin_port=htons(4005);
        bind(sock,(struct sockaddr*)&servaddr,sizeof(servaddr));
        listen(sock,5);
        len=sizeof(struct sockaddr_in);
        while(1)
        {
                if((connect=accept(sock,(struct sockaddr*)&cliaddr,&len))>0)
                {
                        printf("\nENTER\n");
                        con++;
                        printf("con %d",con);
                        conarr[con]=connect;
                        for(i=1;i<=con;i++)
                        {
                         write(conarr[i],buf,sizeof(buf));
                         
                        }
                   }
          }
        char op[2];
        FILE *f;
        char pass[100];
	//char i;
        new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);
        sin_size = sizeof their_addr;
	printf("\n hello");
	f = fopen("file.txt", "r");

	while (fgets(pass, 100, f) != NULL)
	    count++;
	op[0] = count + 48;
	op[1] = '\0';
	printf("no of lines:%s", op);
	if ((send(new_fd, op, sizeof op, 0)) == -1)
	    perror("re");
	fseek(f, 0, SEEK_SET);
	count = 0;
	while (fgets(pass, 100, f) != NULL) 
        {
	    if ((send(new_fd, pass, 100, 0)) == -1)
		perror("l");
	}

	fclose(f);
}

Client:

Code:
 #include<string.h>
 #include<sys/socket.h>
 #include<netinet/in.h>
 #include<arpa/inet.h>
 #include<stdio.h>
 #include<netdb.h>
 #include<stdlib.h>
 int main()
 {
         struct sockaddr_in serv;
         struct addrinfo hints;
         int r,sd,nsd,f,w,c,s,snd,lis;
         char buffer[12]="hello world\n",buff[100]="YES";
         char buf[100];
         sd = socket(AF_INET,SOCK_STREAM,0);
         printf("Socket descriptor:_%d_\n",sd);
         serv.sin_family=AF_INET;
         serv.sin_addr.s_addr=inet_addr("10.142.17.123");
         serv.sin_port=htons(4005);
         s=sizeof(serv);
         c=connect(sd,(void *)&serv,s);
         if(c==0)
            printf("%d_connected_%s",c,buffer);
         else
          {
            printf("%d_%d_Error in connection\n",c,s);
            exit(1);
           }
         while(1)
         {
          r = read(sd,buffer,sizeof(buffer));
          if(r>0)
          {
          printf("Server Says :%s\n",buffer);
          printf("\n...");
          w = write(sd,buffer,sizeof(buffer));
          printf("\nSay yes...");

          break;
          }

         }
        int count = 0;
	if ((recv(sd, buf, sizeof buf, 0)) == -1)
	    perror("p");
	printf("\n The no of lines in file is %s", buf);
	count = atoi(buf);
	while (count != 0) 
        {
	    if ((recv(sd, buff, sizeof buff, 0)) == -1)
        	perror("k");
	    printf("\n%s", buff);
	    count--;
	}
 }

In simple the server broadcasts a message to multiple clients.Whichever client responds first will receive the the datas in the file stored in the server.Plz help me to make this program work.

Thank u in advance
 
Old 04-10-2009, 06:38 AM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Let's start with the server...

Use the int socket descriptor (btw, it is not an unsigned int!) that is returned by accept() as a handle to the client that has just connected.

Use the client socket descriptor to begin comm with the client; from your description, it would appear that the client will send a file name that the server should first receive, and then use to open the corresponding file and shoot back the file's contents to the client.

Code:
...

void handleClient(int client_sd);

int main()
{
  int server_sd = socket(AF_INET, SOCK_STREAM, 0);

  struct sockaddr_in sin;
  memset(&sin, 0, sizeof(sin));
  sin.sin_family=AF_INET;
  sin.sin_addr.s_addr=htonl(INADDR_ANY);
  sin.sin_port=htons(4005);

  bind(server_sd, (struct sockaddr*) &sin, sizeof(sin));

  listen(server_sd, 5);

  int       one    = 1;
  socklen_t oneLen = sizeof(one);

  setsockopt(server_sd, SOL_SOCKET, SO_REUSEADDR, (void*) &one, oneLen);

  for (;;)
  {
    int client_sd = accept(server_sd, 0, 0);

    // insert a fork() here if you want to concurrently process
    // multiple clients.

    handleClient(client_sd);
  }

  // will never reach here, but for sake of completeness
  close(server_sd);
  return 0;
}

void handleClient(int client_sd)
{
  char filename[512] = {0};
  int  bytes         = recv(client_sd, filename, sizeof(filename), 0);

  if (bytes > 0)
  {
    FILE* fp = fopen(filename, "r");

    if (fp)
    {
      char line[512] = {0};

      while (!feof(fp))
      {
        if ((bytes = fread(line, 1, sizeof(line) - 1, fp)) > 0)
        {
          send(client_sd, line, bytes, 0);
        }
      }
    }
    else
    {
      const char* bad = "Bad Filename.";

      send(client_sd, bad, strlen(bad), 0);
    }
  }

  close(client_sd);
}
If your code turns out to be more complicated that what I have shown above, then it is probably that factor that is causing you the issues you seem to have every day wrt sockets.

Last edited by dwhitney67; 04-10-2009 at 06:42 AM.
 
Old 04-11-2009, 12:59 AM   #3
vigneshinbox
LQ Newbie
 
Registered: Mar 2009
Posts: 19

Original Poster
Rep: Reputation: 0
Thumbs up

Thanx dwhitney... i am trying with the server..can u give me some changes in the client also plz??
 
Old 04-11-2009, 01:21 AM   #4
vigneshinbox
LQ Newbie
 
Registered: Mar 2009
Posts: 19

Original Poster
Rep: Reputation: 0
Exclamation

Quote:
Originally Posted by dwhitney67 View Post
Let's start with the server...

Use the int socket descriptor (btw, it is not an unsigned int!) that is returned by accept() as a handle to the client that has just connected.

Use the client socket descriptor to begin comm with the client; from your description, it would appear that the client will send a file name that the server should first receive, and then use to open the corresponding file and shoot back the file's contents to the client.

Code:
...

void handleClient(int client_sd);

int main()
{
  int server_sd = socket(AF_INET, SOCK_STREAM, 0);

  struct sockaddr_in sin;
  memset(&sin, 0, sizeof(sin));
  sin.sin_family=AF_INET;
  sin.sin_addr.s_addr=htonl(INADDR_ANY);
  sin.sin_port=htons(4005);

  bind(server_sd, (struct sockaddr*) &sin, sizeof(sin));

  listen(server_sd, 5);

  int       one    = 1;
  socklen_t oneLen = sizeof(one);

  setsockopt(server_sd, SOL_SOCKET, SO_REUSEADDR, (void*) &one, oneLen);

  for (;;)
  {
    int client_sd = accept(server_sd, 0, 0);

    // insert a fork() here if you want to concurrently process
    // multiple clients.

    handleClient(client_sd);
  }

  // will never reach here, but for sake of completeness
  close(server_sd);
  return 0;
}

void handleClient(int client_sd)
{
  char filename[512] = {0};
  int  bytes         = recv(client_sd, filename, sizeof(filename), 0);

  if (bytes > 0)
  {
    FILE* fp = fopen(filename, "r");

    if (fp)
    {
      char line[512] = {0};

      while (!feof(fp))
      {
        if ((bytes = fread(line, 1, sizeof(line) - 1, fp)) > 0)
        {
          send(client_sd, line, bytes, 0);
        }
      }
    }
    else
    {
      const char* bad = "Bad Filename.";

      send(client_sd, bad, strlen(bad), 0);
    }
  }

  close(client_sd);
}
If your code turns out to be more complicated that what I have shown above, then it is probably that factor that is causing you the issues you seem to have every day wrt sockets.


The code u have given me works like the client has to start the interaction first.But what I wanted is like the server should send a message like "Who wants the file??" .This message has to be sent to all the clients that are connected.The client which says "I want" 1st will be given the file data.After that the ip address of the client to which the data is sent has to be stored in a variable.Most importantly the file should be sent to only one client.Plz help me in this.Because i have been struggling with this for the past one week.I am new to Socket programming ,so i couldn't figure out the actual working of the sockets.I wrote the code with a little knowledge abt sockets.
 
Old 04-11-2009, 07:31 AM   #5
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Everybody is going to have different requirements for their socket application. However, the fundamentals never change.

I have stated this before... for a TCP server, at a minimum, it must do the following:

1. Create a socket
2. Bind the socket
3. Configure any socket options (e.g. Reuse address)
4. Listen on the socket
5. Accept client connections

And whatever happens next is application specific.


For the TCP client, at a minimum, the following must be done:

1. Create a socket
2. Bind the socket (optional)
3. Connect to the server

And whatever happens next is application specific.


From your description, "handshaking" needs to take place. Your server is going to send a message to the client; thus the client should initially be in receive-mode... that is, waiting to receive a message.

So within the server, the handleClient() function could be something like:
Code:
void handleClient(int client_sd)
{
  const char* fileQuestion = "What file do you want to open?";

  int rtn = send(client_sd, fileQuestion, strlen(fileQuestion), 0);

  if (rtn == strlen(fileQuestion))
  {
    char fileName[256] = {0};

    rtn = recv(client_sd, fileName, sizeof(fileName) - 1, 0);

    if (rtn > 0)
    {
      // open file

      // send() file contents to the client; make sure to terminate if send() fails (e.g. the
      // client disconnects prematurely)
    }
  }

  close(client_sd);
}
Since you are planning to handle more than one client, the server should fork() before calling handleClient(). Or alternatively, a multi-threaded application can be developed. For now, I would just stick with the fork() and make sure the child-process terminates after disconnecting the client.

Code:
...

for (;;)
{
  int client_sd = accept(server_sd, 0, 0);

  if (client_sd > 0 && fork() == 0)
  {
    // in child process
    handleClient(client_sd);
    exit(0);
  }

  // parent continues (essentially, loops back)
}
...
As for the client application, the specific part is the opposite of the server. Initially the client awaits using a recv(), and upon receiving the query, sends back a response filename (maybe derived from user input?), and then enters a loop where it will receive the file contents until the connection is terminated. You will know the connection has been terminated when recv() returns a 0.

You may also want to use select(), but for your needs, it may not be necessary. After all, you are monitoring only one socket descriptor at any particular time.
 
Old 04-11-2009, 04:14 PM   #6
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
If you plan to use their_addr for anything, you need to reverse the order of these lines:
Code:
        new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);
        sin_size = sizeof their_addr;
Your original code has sin_size uninitialized. Unless it just so happens to be sizeof(struct sockaddr_in), you probably won't get any information inserted into their_addr by accept. I'm glad to see you use sizeof their_addr rather than sizeof(their_addr), which is used for sizing type names.
Kevin Barry
 
Old 04-11-2009, 08:21 PM   #7
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Quote:
Originally Posted by ta0kira View Post
...
I'm glad to see you use sizeof their_addr rather than sizeof(their_addr), which is used for sizing type names.
Kevin Barry
I never realized there was a distinction. Can you provide a simple example of where the two sizeof styles would return a different result. I am curious because I tend to always use the sizeof with the parenthesis for easier code reading, and depending on my mood, I either insert the variable or its type.
 
Old 04-14-2009, 07:47 AM   #8
vigneshinbox
LQ Newbie
 
Registered: Mar 2009
Posts: 19

Original Poster
Rep: Reputation: 0
Thumbs up

Quote:
Originally Posted by dwhitney67 View Post
Everybody is going to have different requirements for their socket application. However, the fundamentals never change.

I have stated this before... for a TCP server, at a minimum, it must do the following:

1. Create a socket
2. Bind the socket
3. Configure any socket options (e.g. Reuse address)
4. Listen on the socket
5. Accept client connections

And whatever happens next is application specific.


For the TCP client, at a minimum, the following must be done:

1. Create a socket
2. Bind the socket (optional)
3. Connect to the server

And whatever happens next is application specific.


From your description, "handshaking" needs to take place. Your server is going to send a message to the client; thus the client should initially be in receive-mode... that is, waiting to receive a message.

So within the server, the handleClient() function could be something like:
Code:
void handleClient(int client_sd)
{
  const char* fileQuestion = "What file do you want to open?";

  int rtn = send(client_sd, fileQuestion, strlen(fileQuestion), 0);

  if (rtn == strlen(fileQuestion))
  {
    char fileName[256] = {0};

    rtn = recv(client_sd, fileName, sizeof(fileName) - 1, 0);

    if (rtn > 0)
    {
      // open file

      // send() file contents to the client; make sure to terminate if send() fails (e.g. the
      // client disconnects prematurely)
    }
  }

  close(client_sd);
}
Since you are planning to handle more than one client, the server should fork() before calling handleClient(). Or alternatively, a multi-threaded application can be developed. For now, I would just stick with the fork() and make sure the child-process terminates after disconnecting the client.

Code:
...

for (;;)
{
  int client_sd = accept(server_sd, 0, 0);

  if (client_sd > 0 && fork() == 0)
  {
    // in child process
    handleClient(client_sd);
    exit(0);
  }

  // parent continues (essentially, loops back)
}
...
As for the client application, the specific part is the opposite of the server. Initially the client awaits using a recv(), and upon receiving the query, sends back a response filename (maybe derived from user input?), and then enters a loop where it will receive the file contents until the connection is terminated. You will know the connection has been terminated when recv() returns a 0.

You may also want to use select(), but for your needs, it may not be necessary. After all, you are monitoring only one socket descriptor at any particular time.








Thanx dwhitney I somehow got what i want.Thanx for ur valuable responses.
 
Old 04-14-2009, 07:55 PM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by dwhitney67 View Post
I never realized there was a distinction. Can you provide a simple example of where the two sizeof styles would return a different result. I am curious because I tend to always use the sizeof with the parenthesis for easier code reading, and depending on my mood, I either insert the variable or its type.
If they work in the opposite situations they should still return the correct values; however, I believe the distinction is a standard. Sometimes your code won't compile if you use the incorrect pattern, at least in my experience. It also makes your code a little more clear.
Kevin Barry
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Problem in perl Socket program in windows alix123 Programming 2 10-04-2008 11:08 AM
socket program in kernel mathimca05 Linux - Kernel 1 01-21-2008 06:01 PM
Socket Program in Linux Driver mathimca05 Linux - Newbie 2 01-04-2008 02:44 AM
Help me with this socket address bind program. rnice Linux - Networking 0 09-17-2004 07:33 PM
droped packets? problem with socket program... kamel Programming 0 06-01-2004 10:58 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:52 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration