Я новичок в программировании сокетов на C, и я хочу написать прототип сервера-клиента, где сервер будет выступать в качестве своего рода файлообменника для нескольких пользователей (используя TCP протокол). Поскольку сервер и клиент должны иметь возможность принимать команды из stdin, я использовал функцию select(). Это код для двух частей моей программы, и проблема заключается в следующем:
Поскольку сервер и клиент должны иметь возможность принимать команды из stdin и обрабатывать их, а сервер должен отправить ответ на запрос клиента, программа блокирует в определенный момент, и сервер отправляет ответ только после того, как клиент отправил другой запрос. Я думаю, что это происходит из-за использования send() и recv() в то же время в файле server.c, но я не совсем уверен.Модули сервера/клиента Мультиплексирование ввода-вывода
server.c
while(1) {
if (select(maxfd+1,&tmpfds,NULL,NULL,NULL) == -1) {
error("Err in select");
}
for(i = 0; i < maxfd; i++) {
if(FD_ISSET(i,&tmpfds) {
if (i == listenfd) {
< add new client to list >
}
else if (i == 0) { /* keyboard input */
< parse server commands >
}
else {
/* This is where I think my problem is*/
recv(i,buffer,BUFLEN,0);
process(buffer);
send(i,buffer,BUFLEN,0);
}
}
}
client.c
while(1) {
if(select(fdmax+1,&tmpfds,NULL,NULL,NULL) == -1) {
error("Err in select");
}
if (FD_ISSET(0,&tmpfds)) {
fgets(buffer,BUFLEN,stdin);
process_request(buffer);
send(serverfd,buffer,BUFLEN,0);
}
else if (FD_ISSET(serverfd,&tmpfds)) {
recv(serverfd,buffer,BUFLEN,0);
process_response(buffer);
}
}
Кроме того, пожалуйста, не делать никаких резких комментариев о моем кодирования стиля или привычки C. Я ни при каких обстоятельствах не эксперт по С и не утверждаю, что я только учился, поэтому, пожалуйста, помогите мне. Что я делаю неправильно и как я могу избежать этого, не изменяя (слишком много) поведение моей программы?
По умолчанию блокировка 'recv' блокируется по умолчанию. Вы можете установить таймаут с помощью 'setsockopt'. – chrisd1100
Кроме того, вам необходимо управлять данными 'fd_set' в цикле, которые вы не заметили, Linux [' select' tutorial] (http://linux.die.net/man/2/select_tut) заявляет, что «Поскольку select() изменяет свои файловые дескрипторы, если вызов используется в цикле, то перед каждым вызовом набор должен быть повторно инициализирован». – Myst
P.S. если вы используете linux, предпочитайте 'epoll' над' select'. Если вы используете BSD, предпочитайте 'kqueue' над' select'. Windows имеет Overlapping IO, а Solaris имеет 'evpoll' ... рассмотрите возможность использования библиотеки абстракции (то есть' libev'), если ваш код будет работать в разных системах ... Удачи! – Myst