![]() |
| | #1 |
| Registered User Join Date: Apr 2009
Posts: 9
| Multiplexing read socket and stdin I'm having some trouble doing some multiplexing with my script. I'm trying to wait on data either from the socket or stdin but for some reason my code keeps blocking right at the select statement. I think the code needs to be looked at by fresh (and more experienced) eyes. Here's my code to connect to the server: Code: static void connect_to_server() {
struct hostent *hp;
struct sockaddr_in r;
if ((hp = gethostbyname(host)) == NULL) {
fprintf(stderr, "%s: no such host\n", host);
exit(1);
}
if (hp->h_addr_list[0] == NULL || hp->h_addrtype != AF_INET) {
fprintf(stderr, "%s: not an internet protocol host name\n", host);
exit(1);
}
if ((serverfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset((char *) &r, '\0', sizeof r);
r.sin_family = AF_INET;
memcpy((char *) &r.sin_addr, hp->h_addr_list[0], hp->h_length);
r.sin_port = htons(port);
if (connect(serverfd, (struct sockaddr *) &r, sizeof r) < 0) {
perror("connect");
exit(1);
}
// Establish file descriptor lists for stdin and server reading.
FD_ZERO(&fdlist);
FD_SET(serverfd, &fdlist);
FD_SET(fileno(stdin), &fdlist);
}
Code: static void do_something() {
printf("do something\n");
char *q;
if ((q = memnewline(buf, bytes_in_buf))) {
do_something_server(q);
} else {
printf("do switch %d\n", serverfd);
switch (select(serverfd + 1, &fdlist, NULL, NULL, NULL)) {
case 0:
printf("SELECT RETURN 0\n");
break;
case -1:
perror("select");
break;
default:
printf("fdisset\n");
if (FD_ISSET(fileno(stdin), &fdlist)) {
if (! fgets(buf, sizeof buf, stdin)) {
if (ferror(stdin)) {
perror("stdin");
exit(1);
}
}
char **cmd_options = explode(buf);
docmd(cmd_options);
} else if (FD_ISSET(serverfd, &fdlist)) {
printf("server\n");
int n;
if ((n = read(serverfd,
buf + bytes_in_buf,
sizeof(buf) - bytes_in_buf)) == -1) {
perror("read");
exit(1);
}
bytes_in_buf += n;
}
}
}
}
It's seriously ........ing me off. Heh. Thanks in advance, Dave |
| redcameron is offline | |
| | #2 |
| +++ OK NO CARRIER Join Date: Oct 2001
Posts: 10,643
| You can't get the input stream to not-block with anything standard (that's why there's no standard 'getch'). Stop trying to read from stdin and see if it starts working. Quzah.
__________________ Hundreds of thousands of dipshits can't be wrong. Are you up for the suck? |
| quzah is offline | |
| | #3 |
| Registered User Join Date: Apr 2009
Posts: 9
| I commented out the entire fgets part and still nothing. I'm not really understanding what you mean...heh. Can we simply it a bit? I don't want to not-block for stdin, but when I give it data it doesn't react... |
| redcameron is offline | |
| | #4 |
| Senior software engineer Join Date: Mar 2007 Location: Portland, OR
Posts: 5,768
| fgets() attempts to read an entire line of input. If it does not see a newline, it will block. Your select() is probably working correctly -- there is SOME data available, but not enough for an entire line. You need to move away from using fgets() and input the data directly with fread(). If an entire line is not yet available, you need to loop again and wait for the rest of it.
__________________ "Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot |
| brewbuck is offline | |
| | #5 |
| Registered User Join Date: Apr 2009
Posts: 9
| Hmmm, it *does* seem to be blocking on select() because I put a printf() on my default switch case in case it reaches that point. I'm using fgets to retrieve data that WILL have a new line no matter what. So that's definitely not the issue either. |
| redcameron is offline | |
| | #6 |
| Senior software engineer Join Date: Mar 2007 Location: Portland, OR
Posts: 5,768
| If select() is blocking then no data is ready. What are you expecting?
__________________ "Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot |
| brewbuck is offline | |
| | #7 |
| Registered User Join Date: Apr 2009
Posts: 9
| Sorry of this sounds rude, I appreciate the help, but maybe you should re-read what I'm trying to accomplish here. I'm writing a small game application for the command-line which either reacts to server input OR to user input. At the moment I'm trying to give it input but it blocks indefinitely and doesn't reach the point where I'm doing my fgets(). Here is a much simpler and full piece of code I've written and am now testing with: Code: #include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
static char *host = "localhost";
static int port = 1234;
int serverfd;
int bytes_in_buf = 0;
char buf[200];
static void connect_to_server();
static void do_something();
char *memnewline(char *p, int size);
static void clear_buf();
static fd_set fdlist;
static void do_handle_setup();
int main(int argc, char **argv) {
connect_to_server();
do_handle_setup();
clear_buf();
while (1) {
do_something();
}
return 0;
}
static void clear_buf() {
memset(buf, '\0', sizeof(buf));
bytes_in_buf = 0;
}
static void connect_to_server() {
struct hostent *hp;
struct sockaddr_in r;
if ((hp = gethostbyname(host)) == NULL) {
fprintf(stderr, "%s: no such host\n", host);
exit(1);
}
if (hp->h_addr_list[0] == NULL || hp->h_addrtype != AF_INET) {
fprintf(stderr, "%s: not an internet protocol host name\n", host);
exit(1);
}
if ((serverfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset((char *) &r, '\0', sizeof r);
r.sin_family = AF_INET;
memcpy((char *) &r.sin_addr, hp->h_addr_list[0], hp->h_length);
r.sin_port = htons(port);
if (connect(serverfd, (struct sockaddr *) &r, sizeof r) < 0) {
perror("connect");
exit(1);
}
int n;
while (memnewline(buf, bytes_in_buf) == NULL) {
if ((n = read(serverfd,
buf + bytes_in_buf,
sizeof(buf) - bytes_in_buf)) == -1) {
perror("read");
exit(1);
}
bytes_in_buf += n;
}
// Establish file descriptor lists for stdin and server reading.
FD_ZERO(&fdlist);
FD_SET(serverfd, &fdlist);
FD_SET(fileno(stdin), &fdlist);
}
static void send_to_server(char *data) {
if (write(serverfd, data, strlen(data)) != strlen(data)) {
perror("write");
exit(1);
}
}
static void do_handle_setup() {
printf("%s\n", "Give handle:\n");
fgets(buf, sizeof(buf), stdin);
send_to_server(buf);
}
static void do_something() {
char *q;
if ((q = memnewline(buf, bytes_in_buf))) {
printf("server: %s\n", buf);
clear_buf();
} else {
printf("select\n");
switch (select(serverfd + 1, &fdlist, NULL, NULL, NULL)) {
case 0:
break;
case -1:
perror("select");
break;
default:
if (FD_ISSET(fileno(stdin), &fdlist)) {
if (! fgets(buf, sizeof buf, stdin)) {
if (ferror(stdin)) {
perror("stdin");
exit(1);
}
}
} else if (FD_ISSET(serverfd, &fdlist)) {
int n;
if ((n = read(serverfd,
buf + bytes_in_buf,
sizeof(buf) - bytes_in_buf)) == -1) {
perror("read");
exit(1);
}
bytes_in_buf += n;
}
}
}
}
char *memnewline(char *p, int size) /* finds \r _or_ \n */
/* This is like min(memchr(p, '\r'), memchr(p, '\n')) */
/* It is named after memchr(). There's no memcspn(). */
{
for (; size > 0; p++, size--)
if (*p == '\r' || *p == '\n')
return(p);
return(NULL);
}
|
| redcameron is offline | |
| | #8 |
| Senior software engineer Join Date: Mar 2007 Location: Portland, OR
Posts: 5,768
| Again, if select() is blocking, there is no data available on the fd. You could be running into a buffering issue where stdin has already been read into the buffer, but no data is immediately waiting on the fd. Try putting stdin into non-buffered mode and see if that helps. If not, then there is no data available, even if you think there should be.
__________________ "Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot |
| brewbuck is offline | |
| | #9 |
| Registered User Join Date: Apr 2009
Posts: 9
| No you're still not understanding the issue. Either way, I've resolved it. If you're wondering what was wrong, I was setting my masks in the wrong place, select apparently modifies the list every time so they need to be reset on every iteration - something I failed to realise earlier. This is what fixed it: Code: while (1) {
// Establish file descriptor lists for stdin and server reading.
FD_ZERO(&fdlist);
FD_SET(serverfd, &fdlist);
FD_SET(fileno(stdin), &fdlist);
do_something();
}
|
| redcameron is offline | |
![]() |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| socket programming question, closing sockets... | ursula | Networking/Device Communication | 2 | 05-31-2009 05:17 PM |
| Help With Socket Programming | namasteall2000 | Networking/Device Communication | 8 | 02-17-2009 12:58 PM |
| socket error | xlordt | Networking/Device Communication | 2 | 09-25-2003 12:39 AM |
| STDIN stdout | GreyMattr | Linux Programming | 2 | 08-01-2002 01:29 PM |