Я получаю очень странное поведение со своим кодом сокета клиента TCP, поэтому я написал простую тестовую программу.
Код ниже предназначен для постоянной повторной попытки подключения к серверу (127.0.0.1:36000
) пока не соединится. Компилируется с g++ 4.8.5
с -std=c++98
(C ++ 03/11 не может быть использован).
#include <arpa/inet.h>
#include <cctype>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
int sd = -1;
while (true)
{
close(sd);
std::cout << "trying to connect" << std::endl;
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
std::cerr << strerror(errno) << std::endl;
continue;
}
std::cout << "socket created " << sd << std::endl;
struct sockaddr_in addr;
memset((char *)&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
if (!inet_aton("127.0.0.1", &addr.sin_addr))
{
std::cerr << strerror(errno) << std::endl;
continue;
}
std::cout << "translated ip" << std::endl;
addr.sin_port = htons(36000);
if (connect(sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
{
std::cerr << "Error connecting socket" << std::endl;
continue;
}
std::cout << "connected " << inet_ntoa(addr.sin_addr) << ":" << ntohs(addr.sin_port) << std::endl;
std::cout << "write " << write(sd, "from client", 11) << std::endl;
char buf[1024] = {0};
int size;
while ((size = read(sd, buf, 1024, 0, NULL, NULL)) > -1)
{
buf[size] = 0;
std::cout << "received " << size << " [" << buf << "]" << std::endl;
}
std::cout << "stopped" << std::endl;
}
return 0;
}
Несмотря на то, что нет сервера или какой-либо другой программы, использующей порт 36000, connect
вызов успешно, как и write
, Я получаю вывод, который выглядит так:
trying to connect
socket created 3
translated ip
Error connecting socket
trying to connect
socket created 3
translated ip
Error connecting socket
...
...
...
trying to connect
socket created 3
translated ip
connected 127.0.0.1:36000
write 11
received 11 [from client]
Если порт изменен на любой другой неиспользуемый порт (35999, 36001 и т. Д.), connect
будет только сбой (соединение отказано). Другие порты никогда не соединяются.
Аргументы recvfrom
не изменяются, если они присутствуют.
Кроме того, это происходит только тогда, когда время ожидания сокета не истекло. Если время сокета истекло, connect
не удастся.
Бег netstat -an
в то время как read
заблокирован вернется
tcp 0 0 127.0.0.1:36000 127.0.0.1:36000 ESTABLISHED
Это происходит на CentOS 6,7 и 7 VMS.
Что происходит? Что-то странное в порте 36000
? Это Centos /connect
ошибка? Я делаю что-то глупое?
Это частичная копия Как вы можете установить TCP-соединение с тем же портом? но это все еще не объясняет, почему это происходит только на порту 36000.
Когда я выполняю вашу программу с запущенным tcpdump, я получаю некоторые интересные результаты.
sudo tcpdump -i lo
...
14:51:16.477170 IP localhost.35988 > localhost.36000: Flags [S], seq 3826079620, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477173 IP localhost.36000 > localhost.35988: Flags [R.], seq 0, ack 3826079621, win 0, length 0
14:51:16.477203 IP localhost.35990 > localhost.36000: Flags [S], seq 2431563950, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477206 IP localhost.36000 > localhost.35990: Flags [R.], seq 0, ack 2431563951, win 0, length 0
14:51:16.477247 IP localhost.35992 > localhost.36000: Flags [S], seq 3688613148, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477250 IP localhost.36000 > localhost.35992: Flags [R.], seq 0, ack 3688613149, win 0, length 0
14:51:16.477282 IP localhost.35994 > localhost.36000: Flags [S], seq 1503921089, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477285 IP localhost.36000 > localhost.35994: Flags [R.], seq 0, ack 1503921090, win 0, length 0
14:51:16.477315 IP localhost.35996 > localhost.36000: Flags [S], seq 2868111150, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477318 IP localhost.36000 > localhost.35996: Flags [R.], seq 0, ack 2868111151, win 0, length 0
14:51:16.477348 IP localhost.35998 > localhost.36000: Flags [S], seq 281293569, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477351 IP localhost.36000 > localhost.35998: Flags [R.], seq 0, ack 281293570, win 0, length 0
14:51:16.477381 IP localhost.36000 > localhost.36000: Flags [S], seq 3196081163, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477386 IP localhost.36000 > localhost.36000: Flags [S.], seq 3196081163, ack 3196081164, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 95720198,nop,wscale 7], length 0
14:51:16.477422 IP localhost.36000 > localhost.36000: Flags [.], ack 1, win 512, options [nop,nop,TS val 95720198 ecr 95720198], length 0
Эти выходные данные показывают, что сокет фактически выполняет TCP-трехстороннее рукопожатие с собой. По какой-то причине (по крайней мере, в CentOS 6.7) порт источника увеличивается на 2, что предотвращает проблему с портами 35999, 36001.
В RFC 793 это говорит об этом типе соединения как одновременное соединение.
Других решений пока нет …