на клиенте:
ret = send(sFS, "PUT:filename", 13, 0); //посылаем команду PUT
...
//send size of file to file server
ret = send(sFS, "SIZE_PUT_FILE:31", 17, 0); //посылаем доп. информацию косаемо этой команды
if(ret == -1) perror("send");
//код возврта — не "-1" — т.е. отсылается
...
на сервере:
(с каждым новым клиентским запросом ассоциируется потокаовая функция
"childThread")
// the child thread
void *childThread(void *param) {
while(true) {
// handle data from a client
if ((nbytes = recv(childSocket, buf, sizeof(buf), 0)) <= 0) {
//вываливаемся...
}
//split the command we got
CommandSpliter c(buf); //спец. класс для парсинга команд
if(c.getCommandName() == "PUT") { // получили команду PUT
//обрабатываем команду PUT
if(ret = recv(childSocket, buf, sizeof(buf), 0) > 0) {
//всегда возвращает нуль и никого не ждет!!! <--------------????
}
}
}
вопрос: почему recv всегда возвращает ноль, и куда девается инфа от send?
Re: сокеты (проблема с приемом/отправкой)
От:
Аноним
Дата:
06.11.03 12:03
Оценка:
Здравствуйте, dr3, Вы писали:
dr3>вопрос: почему recv всегда возвращает ноль, и куда девается инфа от send?
Для WIN32 recv должна возвращвть 0 если соединение было закрыто.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, dr3, Вы писали:
dr3>>вопрос: почему recv всегда возвращает ноль, и куда девается инфа от send?
А>Для WIN32 recv должна возвращвть 0 если соединение было закрыто.
в луинуксе тоже.
еще заморочка:
на клиенте.
клиент отправляет файл на сервер:
//star sending file by bytes
int bytes=0;
int sizeBlock=1;
cout << "sending";
while( (fgets(buf, sizeBlock+1, pFile)) != NULL ) {
cout << ".";
ret = send(sFS, buf, sizeBlock+1 , 0);
if(ret=-1) perror("send");
}
cout << endl;
я думаю в этом и прична, того что recv возвращает нуль..
//
perror выбрасывает сообщение "send:illegal seek"
это уже не смешно
тот жа самый код прекрасно работет при пересылки данных с сервера на клиент
я начал по google лазить с "socket ilegall seek" — там намикают что это глюк библиотеки какаой то.
Здравствуйте, alexku, Вы писали:
A>Здравствуйте, dr3, Вы писали:
dr3>>вопрос: почему recv всегда возвращает ноль, и куда девается инфа от send?
A>А ты волшебной функцией select пользуешься? A>В твоём сокете просто может не быть данных в данный момент.
A>А вообще-то маловато кода, чтобы понять, что ты делаешь.
Очень даже может быть что дело в этом. Я чесно говоря не совсем понял логику работы seclect, хотя пытался ее втиснуть в код. Был бы благодарен если бы подсказали.
Итак напоминаю.
Есть сервер, есть клиен.
1 Клиент должет уметь получать(перекачать) файл с сервера
2 Клиент должет уметь отправить(закачать) файл на сервер
проблема в том что пункт 2 не выполняется, сообщения не доходят до сервера.
код:
сервер:
см. обработчик команды "PUT":
//CommandSpliter - класс - выделяет комманды закодированные в спец протокол обмена
/*
* fserver.cpp -- a fileServer
*/#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>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
#include"commandSpliter.h"int PORT = 20001; // port we're listening onint listener; // listening socket descriptorint fdmax;
struct client_param {
int socket;
char* clientIP;
};
// the child threadvoid *childThread(void *param) {
char buf[1024];
int nbytes;
//struct client_param* p = (struct client_param*) param;
int childSocket = p->socket;
string clientIP = p->clientIP;
while(true) {
// handle data from a clientif ((nbytes = recv(childSocket, buf, sizeof(buf), 0)) <= 0) {
// got error or connection closed by clientif (nbytes == 0) {
// connection closed
cout << "connection (" << clientIP << ")" << " was closed\n";
} else {
perror("recv");
}
close(childSocket); // bye!
pthread_exit(0);
}
//printf("%s\n", buf);
//split the command we got
CommandSpliter c(buf);
char strBuf[10];
if(c.getFrom()=="c") //from client?
{
command_attrs attrs;
//get - load from fserver to client it meansif(c.getCommandName()=="GET") {
FILE* pFile = NULL;
attrs = c.getCommandAttrs();
string fileName = attrs[0];
string fileName2 = "file_store/" + fileName;
pFile = fopen(fileName2.c_str(), "rt");
int fSize=0;
if(pFile != NULL) {
//determinate size of file (in bytes)while( (fgets(strBuf, 2, pFile)) !=NULL ) fSize++;
fseek(pFile, 0, SEEK_SET);
//cout << "fSize:" << fSize << endl;
cout << "client (" << clientIP << ") calling GET(" << fileName << ")" << endl;
cout << "sending";
string command;
command = "fs/SIZE_GET_FILE:";
sprintf(strBuf, "%d", fSize);
command += strBuf;
int ret = send(childSocket, command.c_str(), command.length() + 1, 0);
if(ret==-1) perror("send");
//start sending file by bytesint bytes=0;
int sizeBlock=1;
while( (fgets(strBuf, sizeBlock+1, pFile)) != NULL ) {
cout << ".";
send(childSocket, strBuf, sizeBlock+1 , 0);
}
cout << endl;
}
else
{
cout << "The client(" << clientIP << ") FAILED to GETting file from FSERVER" << endl;
int ret = send(childSocket, "fs/ERROR_GET_FILE", 19, 0);
if(ret==-1) perror("send");
continue;
}
} //if(c.getCommandName()=="GET")else
if(c.getCommandName() == "DEL") {
attrs = c.getCommandAttrs();
string fileName = attrs[0];
cout << "client (" << clientIP << ") call DEL(" << fileName << ")" << endl;
int ret = send(childSocket, "DELETED", 8, 0);
perror("send");
}//if(c.getCommandName() == "DEL") {else//put - load from client to file server it meansif(c.getCommandName() == "PUT") {
attrs = c.getCommandAttrs();
string fileName = attrs[0];
string fileName2 = "file_store/" + fileName;
string fSize = attrs[1];
cout << "client (" << clientIP << ") call PUT(" << fileName << "; size: " << fSize << ")" << endl;
//
FILE* pFile = fopen(fileName2.c_str(), "w+t"); //create fileif(pFile==NULL) {
cout << "ERROR: could not create file, when file was putting" << endl;
continue;
}
/*
else {
int ret = send(childSocket, "fs/ERROR_PUT_FILE", 19, 0);
if(ret==-1) perror("send");
}
*/
//not work correcly yet
/*
int ret = recv(childSocket, buf, sizeof(buf), 0);
if(ret==0) {
cout << "bad" << endl;
fclose(pFile);
break;
}
*/
/*
//getting body of file
int cc=0;
while( cc != atoi(fSize.c_str()) ) {
cout << "cc:" << cc << endl;
int ret = recv(childSocket, buf, sizeof(buf), 0);
if(ret==0) {
cout << "bad" << endl;
fclose(pFile);
break;
}
fprintf(pFile, buf); //write in file here
cc++;
}
*/
fclose(pFile);
cout << "The client (" << clientIP << ") saved file (" << fileName << ") on file server sucessfuly" << endl;
}
} //if(c.getFrom()=="c")
} //while
}
int main(int argc, char* args[])
{
cout << "\nThe File Server starting..." << endl;
if(argc > 1) {
PORT = atoi(args[1]);
if(PORT <= 0) {
cout << "ERROR! The first argument must be the port number!" << endl;
return -1;
}
}
struct sockaddr_in myaddr; // server addressstruct sockaddr_in remoteaddr; // client addressint newfd; // newly accept()ed socket descriptorint yes=1; // for setsockopt() SO_REUSEADDR, below
socklen_t addrlen;
pthread_t cThread;
// get the listenerif ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
// lose the pesky "address already in use" error messageif (setsockopt(listener, 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(PORT);
memset(&(myaddr.sin_zero), '\0', 8);
if (bind(listener, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) {
perror("bind");
exit(1);
}
cout << "the File Server started and listening port " << PORT << endl;
cout << "listening..." << endl;
// listenif (listen(listener, 10) == -1) {
perror("listen");
exit(1);
}
// main loopwhile(true) {
// handle new connections
addrlen = sizeof(remoteaddr);
if ((newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen)) == -1) {
perror("accept");
} else {
char* clientIP = inet_ntoa(remoteaddr.sin_addr);
//
client_param param;
param.clientIP = clientIP;
param.socket = newfd;
cout << "\n\nNew connection from "<< clientIP << " ip" << " on " << newfd << " socket;" << endl;
if (pthread_create(&cThread, NULL, childThread, ¶m) <0) {
perror("pthread_create");
exit(1);
}
}
}
return 0;
}
Извини, что долго не отвечал. Не было возможности.
Ты уже разобрался с селектом? Если да, то можешь не читать .
Я посмотрел твой код.
Что тебе нужно делать:
1. Использовать селект при каждом чтении и записи в сокет
2. Проверять возвращаемое функциями recv и send значение ВСЕГДА.
Селект останавливает выполнение процесса/потока до того момента, когда во входном буфере сокета появятся данные, готовые к употреблению или сокет, в который ты собираешься гнать данные, будет готов их принять. Иначе ты впустую тратишь время процессора на бесполезный цикл чтения/записи. Селект можно использовать не только с сокетами, а в принципе с любыми файловыми дескрипторами (по крайней мере с stdin точно можно, про остальное не уверен).
Я не буду повторять man, укажу только главное.
int select(номер_дескриптора_с_максимальным_значением + 1,/*!!!Не количество дескрипторов!!!*/
набор_дескрипторов_для_чтения,/*0 если читать ничего не надо*/
набор_дескрипторов_для_записи,/*0 если записывать ничего не надо*/
набор_дескрипторов_для_исключений,/*ставь смело в 0*/
время_ожидания)
В примере устанавливается на ожидание только один сокет и только на чтение или только на запись, но ты можешь установить их столько, сколько надо и на оба действия. Например, stdin можешь поставить на чтение, а сокет — на запись. Появились данные в stdin — прочитал, готов сокет — записал.
int socketReady(int s, int rw, int sec, int usec) {//rw = 0 - чтение, rw = 1 - записьstruct timeval tv;
fd_set rfds;
fd_set wfds;
fd_set *cfds;
int res;
FD_ZERO(&rfds); //читай man select
FD_ZERO(&wfds);
tv.tv_sec = sec;
tv.tv_usec = usec;
if(!rw) cfds = &rfds; //ожидаем сокет на чтениеelse cfds = &wfds; //ожидаем сокет на запись
FD_SET(s, cfds); //читай man select
//обрати внимание на первый параметр.
//!!!селект сбрасывает значения rfds и wfds, поэтому их надо устанавливать
//перед каждым вызовом селект.
res = select(s + 1, &rfds, &wfds, 0, &tv);
if(res == -1) {
// errorreturn ERROR;
} else if(!res) {
// socket not ready, timeout expiredreturn END_TIMEOUT;
}
//проверяем, готов ли нужный сокетif(FD_ISSET(s, cfds)) //читай man selectreturn READY;
else return ERROR;
}
и дальше
wile(1) {
if(READY == (result = socketReady(s, 0, 10, 0))) { //читаем
currRead = recv(s, readBuff, readBuffLen, 0);
if(currRead = -1) {
//ошибка, проверяем errno и вываливаемся из цикла или нет
} else if(currRead == 0) {
//тоже ненормально, значит сокет на том конце закрыт, вываливаемся из цикла
} else {
//работаем с тем, что получили,
//количество полученного равно currRead
}
} else {
//проверяем, что вернулось и т. д.
}
}
и запись
wile(1) {
if(READY == (result = socketReady(s, 1, 10, 0))) { //пишем
sent = send(s, writeBuff, len, 0);
if(sent = -1) {
//ошибка, проверяем errno и вываливаемся из цикла или нет
} else if(sent < len) {
//записалось не всё, нужно будет дописывать то, что осталось в буфере
} else {
//готовим следующую порцию или заканчиваем
}
} else {
//проверяем, что вернулось и т. д.
//и вываливаемся из цикла, если надо
}
}
И ещё несколько замечаний.
Нет никакого признака того, что из сокета прочитаны все данные. И то, что прочитано меньше, чем размер буфера, не говорит ни о чём. Нужно самостоятельно как-то уведомлять получателя о количестве отправленных данных или о том, что достигнут конец данных (какая-нибудь волшебная завершающая последовательность).
Если из сокета прочитано 0 байт, это значит то, он закрыт на другом конце, а не то, что в него отправлено 0 байт.
Сокет может быть закрыт на запись и открыт на чтение и наоборот. Смотри man 2 shutdown.
Если время ожидания вышло, это говорит только о том, что в читающем сокете до сих пор ничего нет или из пишущего сокета ничего не отправлено получателю (может он там просто забыл читать из сокета). Здесь надо самому принимать решение, что делать.