멀티캐스트 관련 질문입니다.

synus1의 이미지

안녕하세요...
멀티캐스트를 공부하고 있습니다.
제가 간단하게 테스트하고 있는 것은 sender, receive 입니다.
sender에서 멀티캐스트 그룹으로 데이터 송신하고, receive에서는 멀티캐스트 그룹에 가입하여 데이터를 수신합니다. 테스트를 해보니 잘 됩니다.
그러나 sender에서 receiver로 멀티캐스트로 패킷을 단방향으로만 전송을 하고 있는데, 저는 양방향을 원하고 있습니다.
즉, sender에서 receiver로는 멀티캐스트 그룹으로 데이터 전송, receiver에서는 sender가 보낸 데이터를 수신하고, 또한 receiver에서 sender로 일반 udp 패킷 전송을 원합니다. 테스트를 해봤는데, 잘 안되더라구요,,,
안되는 부분 sender.c 의 recvfrom() 에서 데이터 수신이 안됩니다.

원래 안되는 것인지 아니면, 다른 어떤 방법이 있는것인지 궁금하네요..
참고로 receiver에서 sender로 멀티캐스트 전송은 된다는 것을 알고있습니다.
아래는 이 부분에 관한 소스입니다.
<sender.c>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#define TTL 64
#define BUFSIZE 30
void error_handling(char *message);

int main(int argc, char **argv)
{
int send_sock;
struct sockaddr_in multi_addr;
int multi_TTL = TTL;
int state, loop;
FILE *fp;
char buf[BUFSIZE];

if(argc != 3) {
printf("Usage%s<IP> <port>\n", argv[0]);
}

send_sock = socket(PF_INET, SOCK_DGRAM, 0);
if(send_sock == -1)
error_handling("socket() error");

memset(&multi_addr, 0, sizeof(multi_addr));
multi_addr.sin_family = AF_INET;
multi_addr.sin_addr.s_addr = inet_addr(argv[1]);
multi_addr.sin_port = htons(atoi(argv[2]));

state = setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &multi_TTL, sizeof(multi_TTL));

if(state)
error_handling("setsockopt() error");

loop = 0;
state = setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
(void *)&loop, sizeof(loop));

if(state)
error_handling("setsockopt() error");

if((fp = fopen("News.txt", "r"))==NULL)
error_handling("fopen() error");

while(!feof(fp)) {
fgets(buf, BUFSIZE, fp);
sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr*)&multi_addr,
sizeof(multi_addr));
sleep(1);
int str_len;
if((str_len = recvfrom(send_sock, buf, str_len, 0, NULL, 0)) >0)
fputs(buf, stdout);
}

close(send_sock);

return 0;
}

void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);

exit(1);
}

<receiver.c>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>

#define BUFSIZE 30
void error_handling(char *message);

int main(int argc, char **argv)
{
int recv_sock;
struct sockaddr_in addr, send_addr;
int state, str_len;
char buf[BUFSIZE];
//char message[BUFSIZE];
char *message;
struct ip_mreq join_addr;
message = "Thank you";

if(argc != 3) {
printf("Usage%s<IP> <port>\n", argv[0]);
}

recv_sock=socket(PF_INET, SOCK_DGRAM, 0);
if(recv_sock == -1)
error_handling("socket() error");

memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(atoi(argv[2]));

if(bind(recv_sock, (struct sockaddr*) &addr, sizeof(addr))==-1)
error_handling("bind() error");

join_addr.imr_multiaddr.s_addr = inet_addr(argv[1]);
join_addr.imr_interface.s_addr = htonl(INADDR_ANY);

state = setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*) &join_addr, sizeof(join_addr));
// error

if(state) {
printf("state %d\n", state);
perror("setsockopt() error\n");
error_handling("setsockopt() error");
}

while(1) {
int size_send_addr = sizeof(send_addr);
str_len = recvfrom(recv_sock, buf, BUFSIZE-1, 0, (struct sockaddr*)&send_addr, &size_send_addr);
if(str_len < 0) break;
buf[str_len] = 0;
fputs(buf, stdout);
sendto(recv_sock, message, strlen(message), 0, (struct sockaddr*)&send_addr, sizeof(send_addr));
}
close(recv_sock);
return 0;
}

void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);

exit(1);
}

kslee80의 이미지

send_sock 를 통해서 패킷을 받으려면
send_sock 을 port 로 bind 해 줘야겠죠?

하지만, send_sock 은 multicast address 로 패킷을 보내는 역할이니,
이 소켓을 특정 port 로 bind 하는것보다는
대신 다른 소켓을 만들어서 특정 port 로 바인드 하고
그 소켓에 대해서 recvfrom() 을 호출해야겠죠.

조금 더 설명하자면,
multicast 된 패킷을 받아서 송신자에게 응답을 보내는 것은
multicast 와는 별로 상관없는 이야기입니다.
multicast address 에 join 한 소켓으로부터 recvfrom() 을 통해
multicast 된 패킷을 받은 경우, recvfrom() 에 인자로 넘어가는
4, 5 번째 아규먼트에는 multicast address 가 아닌,
multicast address 로 패킷을 보낸 호스트가 들어있죠.
그렇기 때문에, multicast 된 패킷을 받고 응답을 보낼 때에는
udp unicast 처럼 해 주면 됩니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.