|
Home > Archive > Unix Programming > February 2004 > Help with Select
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
|
|
| Marcia Hon 2004-02-14, 2:34 am |
| 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[i] = 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;
}
| |
| Marcia Hon 2004-02-14, 2:34 am |
| Hi,
Problem fixed! I put FD_SET, FD_CLR, select, FD_ISSET all inside the loop.
Thanks for your help.
Marcia
| |
| Fernando Gont 2004-02-14, 5:34 am |
| On Sat, 14 Feb 2004 15:42:52 GMT, "Marcia Hon" <honm@rogers.com>
wrote:
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.
--
Fernando Gont
e-mail: fernando@ANTISPAM.gont.com.ar
[To send a personal reply, please remove the ANTISPAM tag]
| |
| James Carlson 2004-02-20, 5:34 am |
| "Marcia Hon" <honm@rogers.com> writes:
> 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.
--
James Carlson, IP Systems Group <james.d.carlson@sun.com>
Sun Microsystems / 1 Network Drive 71.234W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.497N Fax +1 781 442 1677
|
|
|
|
|