Всем доброго времени суток! Решил написать сетевое приложение которое должно обладать следующими свойствами:должно быть одновременно и клиентом и сервером, передавать данные по протоколам TCP и UDP. Возникло несколько вопросов: можно ли сокет настроенный в качестве клиента не убивая перестроить на сервер? какой максимальный объем данных может быть передан за один раз? Как регулировать размер данных при передаче, писать свой протокол прикладного уровня? возможна ли одновременная работа двух или более блокирующих сокетов при запуске их в различных потоках?
Честно говоря странный вопрос, да и зачем нужны такие фокусы? Что мешает использовать два разных сокета? Имеется ввиду в одном пакете? UDP - чуть меньше 64 кб. Если юзать TCP, это вообще не имеет значения. Да. Это придется делать в любом случае. Да.
Sholar Спасибо вам огромное. дело в том, что в качестве клиента сокет нужен будет лишь для передачи имени хоста и ip адреса серверу к которому уже подключен и ожидает имя и адрес другой клиент. Получив их он должен будет соединиться с сервером на указанный ip и на тот же порт.
Всем снова здравствуйте! Подскажите пожалуйста как работает recv? Я использую блокирующий сокет. Когда recv вернет управление? Например: recv(s,char buf[1000],len(1000-1),0); а ответ от сервера будет размером <1000 она вернет управление или нет? Если да, то у меня почему то все виснет может это значит, что сервер вообще ответ не шлет? Что тогда делать? Может запускать recv отдельным тредом и если он зависнет прибивать его, а затем повторять запрос и снова запускать тред с recv? И еще такой вопрос: у меня два компа в сети, подключены через адсл-модем, который настроен в режим роутера. Можно ли как-то программным путем узнать глобальный ip-адрес компа? И как из глобальной сети обратиться к одному из моих компов?
смотря какой сокет. Если TCP - то там нет понятия "длина ответа" - блокирующий сокет вернет управление либо только тогда, когда в потоке накопится не меньше запрошенного количества байт, либо когда оборвется TCP-соединение. Блокирующий же UDP сокет должен возвращать как только появится доступный пакет любого размера.
Сокет ТСР. Первый запрос к серверу такой:"HELO 127.0.0.1".Ответ сервера "220 smtp3.mail.ru ESMTP ready". При этом recv(s,char buf[1000],len(1000-1),0); возвращает 31(число принятых байт) и отдает управление(хотя по вашим словам не должно 31<1000), но после второго запроса виснет наглухо
pashe4ka13, И никаких «когда в потоке накопится не меньше запрошенного количества байт». Подразумеваю, что сокет в блокирующем режиме: после HELO recv возвращает ответ сервера (не обязательно целиком – чтобы считать ответ сервера, может потребоваться и несколько recv, это ваше дело копить данные и звать recv, пока в буфере не появится CRLF, или что там по протоколу), после второго recv сервер ничего не отвечает, ведь команду вы ему не послали, и recv «виснет наглухо», ожидая данных.
h0t При блокирующем сокете первый раз возвращает количество байт(символов) 31, затем виснет наглухо. Разблокировал сокет стало при втором вызове выдавать WSAEWOULDBLOCK (код 10035)Resource temporarily unavailable. Как я понимаю почтовый сервер не отвечает?
pashe4ka13 Блокирующий режим работы сокета. recv/read на таком сокете блокируется, если в ядерном буфере приёма данных из сети пусто. Если же в буфере что-то есть, то возвращается то, что есть. Точнее та часть того что есть, которая влезет в переданный юзерский буфер. При этом, не знаю как там в венде, в *nix, есть ещё одна хитрость: при последовательных recv/read на сокете, которые "вычитывают" всё содержимое ядерного буфера, последний вызов который не заблокируется всегда вернёт меньше байт, чем запрошено. То есть, допустим в ядерном буфере 10 байт. Мы читаем по 3 байта за раз. Значит первые три раза ядро нам будет возвращать по три байта, в четвёртый раз ядро вернёт один байт, пятый вызов заблокируется. Если мы читаем по 5 байт за раз, то ядро дважды вернёт нам по 5 байт, в третий раз вернёт 0 байт, и четвёртый вызов заблокируется. Неблокирующий режим. Ядро не блокирует вызовы никогда, но возвращает либо ненулевое количество байт (если есть что возвращать), либо -EWOULDBLOCK. У вас же возникает EWOULDBLOCK, я думаю потому, что просто протоколы вы не выдерживаете. smtp ведь чётко работает по правилу клиент отправил запрос, сервер прислал ответ. Сервер не "не отвечает", а ждёт следующего запроса, на который можно ответить.
Да действительно сервер не шлет ответа. Если я делаю вызов так Код (Text): bool SendData() { char buffer[]= "HELO 127.0.0.1\r\n"; if (send(сокет.СокетСервера,buffer,sizeof(buffer),0)==SOCKET_ERROR)return false; return true; } то все работает и recv не виснет, но если я вызываю функцию передачи так Код (Text): bool SendData(char buffer[]) { if (send(сокет.СокетСервера,buffer,sizeof(buffer),0)==SOCKET_ERROR)return false; return true; } int main() { SendData("HELO 127.0.0.1\r\n"); return 0; } то виснет, хотя SendData возвращает true.
pashe4ka13, и чему, по вашему, равно sizeof(buffer) во втором случае? r90, где про это можно прочитать? Везде только “… return the length of the message on successful completion.” и “The return value will be 0 when the peer has performed an orderly shutdown”. И как в таком случае предполагается отличать нормально закрытый сокет от состояния, когда данные кончились?
ASMatic Я предвидел, что это кто то скажет. SendData(); до посылки сюда была ПередачаДанных(); Я не придерживаюсь какой либо нотации и стандарта при написании кода, так как написание простеньких прог это мое хобби и не думаю, что кто то в дальнейшем будет читать мой быдлокод. А то что Сокет не стал Socket при отправки сюда, это моя невнимательность. Вы бы лучше ответили на второй вопрос как получить ip находясь за NATом. Я, как вариант, думаю отправить запрос сервису который определяет ip и распарсить его html ответ 'выдрав' от туда свой адрес. Но даже получив глобальный адрес как обратиться к конкретному компу?
iZzz32 sizeof(buffer) будет равно 4 байта, то есть длинна указателя. А как можно передать корректное значение в функцию? Мне в голову приходит только передача отдельно указателя и длинны Код (Text): bool SendData(char *buffer, int len) { if (send(сокет.СокетСервера,buffer,len,0)==SOCKET_ERROR)return false; return true; } Может можно как-то красивее?
Всем большое спасибо! Заменил sizeof на strlen все работает теперь как надо, остался лишь вопрос как из глобальной сети получить доступ к компу который находиться за NATом?
а потом в привычку войдет...зачем делать не правильно, если изначально можно делать как положено и не тратить время на исправления кода перед постингом на форум.да еще потом нарываться на всякие коментарии (типа мого) и оправдыватся что недоглядел еще там подправить% с доступом за NAT самое постое решение - бекконект.