发送方 获取 绑定 端口 linux c,多播报文的发送和接收

1

实验目的

掌握多播的原理及如何进行多播报文的发送和接受

2

注意事项

需包括

ws2tcpip.h

文件

发送者和所有接受者在同一网内

不考虑

TTL

值,回环状态

通过

setsockopt( )

函数设置选项来实现多播数据的发送和接收

3

试验流程

3.1

多播数据发送端流程

l

创建一个数据报套接口

l

设置多播地址

(

例:

239.192.1.2)

和端口号

(

例:

12345)

l

调用

setsockopt( )

函数设置发送的数据报本地接口

(IP_MULTICAST_IF)

struct in_addr interface_addr;

setsockopt ( socket, IPPROTO_IP, IP_MULTICAST_IF,&interface_addr,

sizeof(interface_addr) );

l

使用

sendto

函数发送数据,目标地址为第二步所设置的多播地址

3.2

多播数据接收的流程

l

创建数据报套接口

l

绑定本地地址

(INADDR_ANY)

和端口号

(

同发送端

)

l

调用

setsockopt( )

函数设置

IP_ADD_MEMBERSHIP

选项,加入多播组

struct ip_mreq {

struct in_addr imr_multiaddr;

/* IP multicast address of group */

struct in_addr imr_interface;

/* local IP address of interface */

};

struct ip_mreq mreq;

setsockopt ( socket, IPPROTO_IP,

IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)

);

l

接收数据

4

源代码

4.1

公共代码

#ifndef _MCASTLIB_H_

#define _MCASTLIB_H_

#include

#include

#ifdef __cplusplus

extern "C" {

#endif

int mc_join(SOCKET s,

in_addr *mcaddr, in_addr *local_if);

int mc_setIF(SOCKET s,

const DWORD local_out_if);

int mc_getIF(SOCKET s,

DWORD *local_out_if);

int mc_setTTL(SOCKET s,

const DWORD ttl);

int mc_getTTL(SOCKET s,

DWORD *ttl);

int mc_setLoop(SOCKET s,

const BOOL flag);

int mc_getLoop(SOCKET s,

BOOL *flag);

int mc_leave(SOCKET s,

in_addr *mcaddr, in_addr *local_if);

#ifdef __cplusplus

}

#endif

#endif // _MCASTLIB_H_

#include "MCastlib.h"

int mc_join(SOCKET s,

in_addr *mcaddr, in_addr *local_if)

{

ip_mreq mreq;

memcpy(&(mreq.imr_interface), local_if,

sizeof(in_addr)); // local if

memcpy(&(mreq.imr_multiaddr), mcaddr, sizeof(in_addr));

// multicast group address

return (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,

(char*)&mreq, sizeof(mreq)));

}

//

为多播报文设置外出接口

int mc_setIF(SOCKET s,

const DWORD local_out_if)

{

return (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,

(char*)&local_out_if, sizeof(local_out_if)));

}

//

获取多播报文的外出接口

int mc_getIF(SOCKET s, DWORD *local_out_if)

{

int

len = sizeof(DWORD);

return

(getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&local_out_if,

&len));

}

//

设置外出多播报文的

TTL

值,默认为

1

int mc_setTTL(SOCKET s, const DWORD ttl)

{

return

(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&ttl, sizeof(ttl)));

}

//

获取外出多播报文的

ttl

int mc_getTTL(SOCKET s, DWORD *ttl)

{

int

len = sizeof(DWORD);

return

(getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)ttl, &len));

}

//

启用或者禁止多播报文环回

int mc_setLoop(SOCKET s, const BOOL flag)

{

return

(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&flag, sizeof(flag)));

}

//

获取本地多播回环状态

int mc_getLoop(SOCKET s, BOOL *flag)

{

int

len = sizeof(BOOL);

return

(getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)flag, &len));

}

//

本地接口

local_if

离开多播组

int mc_leave(SOCKET s, in_addr *mcaddr,

in_addr *local_if)

{

ip_mreq

mreq;

memcpy(&(mreq.imr_interface),

local_if, sizeof(in_addr)); // local if

memcpy(&(mreq.imr_multiaddr),

local_if, sizeof(in_addr)); // multicast group address

return

(setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&mreq,

sizeof(mreq)));

}

4.2

发送方

//

发送方

#pragma comment(lib, "ws2_32.lib")

#include

#include

#include "MCastlib.h"

void HandleError(char *func);

int main()

{

WSAData

wsaData;

WSAStartup(WINSOCK_VERSION,

&wsaData);

/*********

创建一个数据报套接口

****************/

sockaddr_in

local;

memset(&local,

0, sizeof(local));

local.sin_addr.s_addr

= htonl(INADDR_ANY);

local.sin_family

= AF_INET;

local.sin_port

= htons(12345);

SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);

/*********************************************/

/****

调用

setsockopt( )

函数设置发送的数据报本地接口

(IP_MULTICAST_IF)****/

if

(mc_setIF(sock, sizeof(sock))

== SOCKET_ERROR)

{

printf("mc_setIF:

%d\n", WSAGetLastError());

}

/**********************************************************************/

/*

//

获取默认的多播报文

TTL

值和回环状态

DWORD

ttl;

if

(mc_getTTL(sock, &ttl) == SOCKET_ERROR)

{

printf("mc_getTTL:

%d\n", WSAGetLastError());

}

BOOL

loop;

if

(mc_getLoop(sock, &loop) == SOCKET_ERROR)

{

printf("mc_getLoop:

%d\n", WSAGetLastError());

}

printf("Multicast

default: TTL=%d,LoopBack=%d\n", ttl, loop);

//

设置

TTL

值为

219

ttl

= 219;

if

(mc_setTTL(sock, ttl) == SOCKET_ERROR)

{

printf("mc_setTTL:

%d\n", WSAGetLastError());

}

*/

/***************

设置多播地址和端口号

*************/

sockaddr_in to;

memset(&to, 0, sizeof(to));

to.sin_addr.s_addr = inet_addr("239.192.1.2");

to.sin_family = AF_INET;

to.sin_port = htons(12345);

/************************************************/

/***

使用

sendto

函数发送数据,目标地址为第二步所设置的多播地址

****/

char

buf[60];

while

(true)

{

printf("INPUT:\n");

gets(buf);

buf[strlen(buf)]

= '\0';

int res = sendto(sock, buf, strlen(buf) + 1, 0,

(sockaddr*)&to, sizeof(to));

if

(res == SOCKET_ERROR)

{

HandleError("sendto");

}

else

{

printf("Send

out %d bytes!\n", res);

if

(strcmp(buf, "QUIT") == 0)

{

break;

}

}

}

/***************************************************************/

return

0;

}

void HandleError(char *func)

{

int

errCode = WSAGetLastError();

char

info[65] = {0};

_snprintf(info,

64, "%s: %d\n", func, errCode);

printf(info);

}

4.3

接收方

//

接收方

#pragma comment(lib,

"ws2_32.lib")

#include

#include "MCastlib.h"

int main()

{

//

Init the winsock environment

WSAData

wsaData;

if

(WSAStartup(WINSOCK_VERSION, &wsaData) != 0)

{

printf("Failed

to Load a winsock.\n");

return

0;

}

//

创建数据报套接口

SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);

if

(sock == INVALID_SOCKET)

{

printf("socket:

%d\n", WSAGetLastError());

return

0;

}

//

绑定本地地址

(INADDR_ANY)

和端口号

(

同发送端

)

sockaddr_in

local;

memset(&local,

0, sizeof(local));

local.sin_family

= AF_INET;

local.sin_addr.s_addr

= htonl(INADDR_ANY);

local.sin_port

= htons(12345);

//

bind local socket

if (bind(sock, (sockaddr*)&local, sizeof(local)) ==

SOCKET_ERROR)

{

printf("bind:

%d\n", WSAGetLastError());

return

0;

}

//

多播组地址

in_addr

mcaddr;

mcaddr.S_un.S_addr = inet_addr("239.192.1.2");

//

加入多播组

if (mc_join(sock, &mcaddr, &(local.sin_addr)) ==

SOCKET_ERROR)

{

printf("Join

Multicast Group: %d\n", WSAGetLastError());

}

//

接收数据,考虑此时能收到发往哪些目的地址的

UDP

报文

char

buf[65];

while

(true)

{

memset(buf,

0, 65);

if (recvfrom(sock, buf, 64, 0, NULL, NULL) ==

SOCKET_ERROR)

{

printf("recvfrom:

%d\n", WSAGetLastError());

break;

}

else

{

printf("recvd:

%s\n", buf);

if

(strcmp(buf, "QUIT") == 0)

{

break;

}

}

}

return

0;

}

摘自

好的,以下是一个简单的示例代码,可以实现你想要的功能: 假设你的配置文件 `config.txt` 存放了 IP 地址和端口号,格式如下: ``` IP=192.168.1.10 PORT=12345 ``` 代码如下: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define CONFIG_FILE "config.txt" // 配置文件路径 #define BUFSIZE 1024 // 接收缓冲区大小 int main(int argc, char *argv[]) { int sockfd; struct sockaddr_in server_addr, client_addr; char recv_buf[BUFSIZE]; char ip[16]; // 存放配置文件中的 IP 地址 int port; // 存放配置文件中的端口号 // 打开配置文件 FILE *fp = fopen(CONFIG_FILE, "r"); if (fp == NULL) { perror("fopen"); exit(EXIT_FAILURE); } // 读取配置文件中的 IP 和端口号 char line[256]; while (fgets(line, sizeof(line), fp) != NULL) { if (strncmp(line, "IP=", 3) == 0) { sscanf(line + 3, "%s", ip); } else if (strncmp(line, "PORT=", 5) == 0) { sscanf(line + 5, "%d", &port); } } fclose(fp); // 创建UDP socket if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); exit(EXIT_FAILURE); } // 设置本地地址和端口 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(ip); server_addr.sin_port = htons(port); if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind"); exit(EXIT_FAILURE); } printf("Server listening on %s:%d\n", inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port)); // 循环接收数据 socklen_t client_addr_len; while (1) { memset(recv_buf, 0, BUFSIZE); client_addr_len = sizeof(client_addr); if (recvfrom(sockfd, recv_buf, BUFSIZE, 0, (struct sockaddr *)&client_addr, &client_addr_len) < 0) { perror("recvfrom"); exit(EXIT_FAILURE); } printf("Received message from %s:%d: %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), recv_buf); } // 关闭socket close(sockfd); return 0; } ``` 这个示例代码使用了 Linux 的 socket API,读取了配置文件中的 IP 地址和端口号,并使用这些信息设置了本地地址和端口。然后,创建了一个 UDP socket,并绑定到指定的地址和端口上。最后,使用一个循环接收数据,并打印发送的地址和端口号以及接收到的消息。你可以根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值