Опция сокета C ++ для повторного использования порта - PullRequest
0 голосов
/ 12 апреля 2011

У меня проблема с сокетом c ++.
Я использую CAsyncSocket из MFC, к которому я хочу присоединиться к группе многоадресной рассылки.
Также мне нужно иметь несколько слушателей в этой группе, и вот тут я попал в беду.
Я нашел несколько примеров в Интернете, но, похоже, это не работает.
Вот мой код:

//create socket on port 17233   
BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ);

//set reuse socket option  
BOOL bMultipleApps = TRUE;
bRet = SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);

//join multicast group
ip_mreq m_mrMReq;           // Contains IP and interface of the host group
m_mrMReq.imr_multiaddr.s_addr = inet_addr((LPCSTR)"224.30.0.1");    /* group addr */ 
m_mrMReq.imr_interface.s_addr = htons(INADDR_ANY);      /* use default */

int uRes =setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq));

Нет ошибок при запуске.
Но когда я пытаюсь запустить другой экземпляр приложения, он не может создать новый сокет на этом порту, потому что порт используется.

Я сделал это в C #, и он работал нормально, как это:

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
s.Bind(ipep);
IPAddress ip = IPAddress.Parse(mcastGroup);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip, IPAddress.Any));
s.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.MulticastTimeToLive, int.Parse("1"));

Так что, если какое-либо тело увидит проблему с моим кодом или у меня есть несколько советов, я с радостью буду благодарен.

РЕДАКТ. 1:
Является ли CAsyncSocket TCP-сокетом?

РЕДАКТИРОВАТЬ 2: После прочтения Могут ли два приложения прослушивать один и тот же порт?
Я думаю, что сделал путаницу. Мне нужен многоадресный UDP-порт, к которому может обращаться несколько приложений, используя SO_REUSEADDR

Редактировать для уточнения:

BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ)

Создает сокет UDP и привязывается к порту 17223.
Чтобы SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET); работал, вам нужно установить его перед привязкой, как сказал @Hasturkun.
Окончательный рабочий код выглядит так:

    BOOL bRet = Socket(SOCK_DGRAM, FD_READ);
    if(bRet != TRUE)
    {
        UINT uErr = GetLastError();
        std::cout<<"Error:"<<uErr<<std::endl;
        return FALSE;
    }else{
        std::cout<<"Create sock: OK"<<std::endl;
    }

    //add reuse
    BOOL bMultipleApps = TRUE;      /* allow reuse of local port if needed */
    SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);

    //bind
    bRet = Bind(17233, NULL);
    if(bRet != TRUE)
    {
        UINT uErr = GetLastError();
        std::cout<<"Error(BIND):"<<uErr<<std::endl;
    }else{
        std::cout<<"BIND sock: OK"<<std::endl;
    }

Спасибо
Gabriel

;

Ответы [ 3 ]

2 голосов
/ 12 апреля 2011

Вы должны иметь возможность отделить создание сокета от привязки, создать сокет, используя Socket, например.

BOOL bRet = Socket(SOCK_DGRAM, FD_READ);

Затем свяжите его с Bind после установки сокета

BOOL bMultipleApps = TRUE;
bRet = SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);

bRet = Bind(17233, NULL);
1 голос
/ 12 апреля 2011

Если boost - вариант для вас, рассмотрите возможность использования Asio для этого. Это очень просто и в этом примере показан простой многоадресный приемник.

Важная часть для нескольких слушателей:

socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true));

Если вам неясно, что делает ваше приложение, просто запустите netstat, и вы увидите, например, сокеты и как они связаны (IP, порт и протокол):

netstat -an

... и найдите интересующий вас порт. Если вы запускаете несколько приложений, слушающих один и тот же порт, вы должны увидеть несколько записей для одного и того же порта с UDP в качестве протокола.

1 голос
/ 12 апреля 2011

Это происходит, я думаю, потому что вы привязываете клиентский сокет к определенному порту и адресу.Возможно в его конструкторе:

BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ);

Не следует привязывать сокет клиента к адресу.Позвольте Windows управлять этим для вас.У вас должна быть возможность не создавать сокет, проходящий через определенный порт, или, если вы этого не сделаете, вы должны создать сокет, используя другой порт.

Кроме того, опция BOOL bMultipleApps = TRUE; работает не так, как вы думаетеоно делает.Он устанавливает задержку в сокете, но после создания и прослушивания сокет (я имею в виду порт сокета) не может использоваться в других приложениях, независимо от того, что вы делаете.

Проверьте это: так-linger-and-close-socketswinsock

РЕДАКТИРОВАТЬ:

Я также не знаю, что значение port в вашем коде C #:

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);

Вы уверены, что port не получает другое значение при каждом запуске приложения?

Как я уже сказал, попробуйте создать сокет в другомпорт, чтобы увидеть, что происходит.Google для so_linger, чтобы узнать, что это значит.

РЕДАКТИРОВАТЬ 2:

Взгляните на: Могут ли два приложения прослушивать один и тот же порт?

РЕДАКТИРОВАТЬ 3:

Возможно, ваш код c #:

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);

привязывает адрес к другой сетевой карте.У вас 2 компьютера на одном компьютере?Если вы это сделаете, вы можете связать один и тот же порт в обоих из них.

РЕДАКТИРОВАТЬ 4:

Пример использования UDP-сокетов: Отправка и получение дейтаграмм UDPс CAsyncSocket MFC

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...