Help with Select

M

Marcia Hon

Hi,

I am trying to use the select() socket programming command to select between
stdin and a connection. Currently, I have a listening stream and stdin that
I insert into the fd_set. The problem is that when I recognize FD_ISSET from
stdin, I am stuck there. The loop does not return me to select() between
stdin and listening socket. Similarly, when I accept a client, the loop does
not return me to select between stdin and listeing socket. I don't know what
to do. I want to be able to select continuously between stdin and the
listening port after I have either accepted from a port or from stdin.

I have pasted the codes that I am using for the listening to port and stdin
and the code for the client.

Please help.

Thank you,

Marcia Hon

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#define max(a, b) ((a) > (b) ? a: b)

int flushToEndOfLine();

int main(int argc, char *argv[])

{

fd_set master;


struct sockaddr_in myaddr;

struct sockaddr_in remoteaddr;


int fdmax;

int listenerSocket;

int newfd;

char buf[256];

int yes = 1;

int addrlen;

int i, j;


if(argc != 2)

{

fprintf(stderr, "Usage: %s <listen_port>\n", argv[0]);

exit(1);

}


FD_ZERO(&master); //clear master set


// get listenerSocket

if((listenerSocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror("socket");

exit(1);

}


// lose socket already in use error message

if(setsockopt(listenerSocket, SOL_SOCKET, SO_REUSEADDR, &yes,

sizeof(int)) == -1) {

perror("setsockopt");

exit(1);

}


// bind

myaddr.sin_family = AF_INET;

myaddr.sin_addr.s_addr = INADDR_ANY;

myaddr.sin_port = htons(atoi(argv[1]));

memset(&(myaddr.sin_zero), '\0', 8);

if(bind(listenerSocket, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1)
{

perror("bind");

exit(1);

}


// listen

if(listen(listenerSocket, 5) == -1) {

perror("listen");

exit(1);

}


FD_SET(listenerSocket, &master);

FD_SET(0, &master);


fdmax = max(listenerSocket, 0);


while(1){

printf("select\n");

if(select(fdmax+1, &master, NULL, NULL, NULL) == -1){

perror("select");

exit(1);

}


if(FD_ISSET(listenerSocket, &master)){

addrlen = sizeof(remoteaddr);

if((newfd = accept(listenerSocket, (struct

sockaddr *)&remoteaddr, &addrlen)) == -1) {

perror("accept");

}

printf("new connection from client\n");

close(newfd);

}

else

{

if(FD_ISSET(0, &master))

{

printf("user entered data \n");

flushToEndOfLine();

}

}

}


return 0;

}

int flushToEndOfLine()

{

int c;

while ( (c=getchar()) != EOF && c != '\n' );

return;

}



client:

//WHAT IF SHORT IS NOT 2 BYTES?!?!?!?

#include <stdio.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#define FILE_TBYTES 4 //bytes at the beginning of file that specify how many
bytes are in this block being sent

#define MAX_BYTES 1000 //breaks up file into this many bytes and sends this
many bytes at a time

#define MAX_BSEND_RETRY 3 //how many times to retry sending a block of
MAX_BYTES before fail

#define DEBUG

//prototypes

int establish_connection (const char * name, unsigned short port);

int send_stream (int sockfd, const char * data, int len);

unsigned long getFileSize(char *fileName);

//check ip or dns

int main(int argc, char *argv[])

{

FILE *fp;

int j; //loop counters

short int i; //this better be 2 bytes

char * buffer;

unsigned long *tmp;

unsigned short port;

int sockfd;

unsigned long fileSize;


if ((buffer = (char *) malloc (MAX_BYTES)) == NULL)

{

fprintf(stderr, "Not enough memory for a file input buffer of %d\n",
MAX_BYTES);

exit(1);

}


//Check if 3 arguments passed

if (argc !=4)

{

fprintf(stderr, "Usage: %s <ip> <port> <file>\n", argv[0]);

exit(1);

}


//no check!

port = atoi(argv[2]);


#ifdef DEFINE

printf("Arguments Passed:\n");

printf("IP: %s\n", argv[1]);

printf("PORT: %d\n", port);

printf("FILE: %s\n", argv[3]);

printf("\n");

#endif



//open file

if ((fp = fopen(argv[3],"r")) == NULL)

{

fprintf(stderr, "Error: Could not open %s\n", argv[3]);

exit(1);

}


if ((sockfd = establish_connection (argv[1], port)) == -1)

{

fprintf(stderr, "Error establishing connection\n");

fclose(fp);

exit(1);

}


//buffer = "Hello World";

//send_stream(sockfd, buffer, 11);


//send file size

fileSize = getFileSize(argv[3]);

tmp = (unsigned long *) &buffer[0];

*tmp = (unsigned long) htonl(fileSize);

send_stream(sockfd, buffer, 4);

printf("File Size: %d\n", fileSize);


while (!feof(fp))

{

//read some bytes

for (i = 0; i<MAX_BYTES; i++)

{

buffer = fgetc(fp);

if (feof(fp)) //end of file true

break;

}



//echo bytes to screen

for (j=0; j<i; j++)

{

//put send function here

//printf("%c", buffer[j]);

}


if (!send_stream(sockfd, buffer, i))

{

fprintf(stderr, "Error sending a block\n");

exit(1);

}

}


//close file

fclose(fp);

close(sockfd);


return 0; //exited succesfully

}



//pass name of the host and port number only!

//-1 fail, sockfd success

int establish_connection (const char * name, unsigned short port)

{

struct sockaddr_in their_addr;

int sockfd;

int r; //returned from functions

struct hostent * h;

sockfd = socket(AF_INET, SOCK_STREAM, 0);


//set up the structure

their_addr.sin_family = AF_INET;

their_addr.sin_port = htons(port); // short, network byte order

memset(&(their_addr.sin_zero), '\0', 8); // zero the rest of the struct


h=gethostbyname(name);

if (h == NULL)

return -1;


//1. make *h_addr_list[0] be a in_addr *

//2. dereference this pointer and assign it to their_addr.sin_addr

their_addr.sin_addr = *((struct in_addr *)h->h_addr);


printf("IP Address : %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));

printf("IP Address : %s\n", inet_ntoa(their_addr.sin_addr));

printf("Port: %d \n", ntohs(their_addr.sin_port));


if((connect(sockfd, (struct sockaddr *) &their_addr, sizeof(struct
sockaddr))) == -1)

return -1;


return sockfd;

}

//sends data

//connect may return that it sent less, this function sends the rest

//return 0 on fail, 1 on success

int send_stream (int sockfd, const char * data, int len)

{

int bytes_sent, newlen;

const void * newdata;


bytes_sent = send(sockfd, data, len,0);

if (bytes_sent < 0)

return 0;

while (bytes_sent < len - 1)

{

//if we sent 10 bytes, we sent bytes 0...9

//need to send byte 10...

newdata = &data[bytes_sent];

bytes_sent = send(sockfd, newdata, len - bytes_sent, 0);

if (bytes_sent < 0)

return 0;

}

return 1;

}

unsigned long getFileSize(char *fileName)

{

unsigned long fileSize;

FILE *f=fopen(fileName, "rb");

if(f==NULL)

{

fprintf(stderr, "Cannot open file.\n");

exit(EXIT_FAILURE);

}

else

{

if(fseek(f, 0, SEEK_END)!=0)

{

fprintf(stderr, "Cannot use file.\n");

exit(EXIT_FAILURE);

}

fileSize=ftell(f);

}

if(fclose(f)!=0)

{

fprintf(stderr, "Cannot close file.\n");

exit(EXIT_FAILURE);

}

return fileSize;

}
 
M

Marcia Hon

Hi,

Problem fixed! I put FD_SET, FD_CLR, select, FD_ISSET all inside the loop.

Thanks for your help.
Marcia
 
F

Fernando Gont

This has nothing to do with ANSI C, so I've removed it from the
Followup-To field. (I should probably have removed
comp.os.linux.networking, too.)

while(1){

printf("select\n");

if(select(fdmax+1, &master, NULL, NULL, NULL) == -1){

perror("select");

exit(1);

}

select() will destroy the "master" parameter each time you call it. So
your code should look like this:


saved_master = master;

while(1){
printf("select\n");

master = saved_master;

if(select(fdmax+1, &master, NULL, NULL, NULL) == -1){
perror("select");
exit(1);
}


BTW, your code is ugly indented. If the bug in your code hadn't been
easy to spot, probably none would have taken the time to have a look
at it.
 
J

James Carlson

Marcia Hon said:
I am trying to use the select() socket programming command to select between
stdin and a connection. Currently, I have a listening stream and stdin that
I insert into the fd_set. The problem is that when I recognize FD_ISSET from
stdin, I am stuck there. The loop does not return me to select() between
stdin and listening socket. Similarly, when I accept a client, the loop does
not return me to select between stdin and listeing socket. I don't know what
to do. I want to be able to select continuously between stdin and the
listening port after I have either accepted from a port or from stdin.

Select modifies its arguments. You need to put the FD_SET invocations
*inside* the loop, or save a copy of 'master' somewhere.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top