linux java 发送和接收指定源组播

kylin3.5国产化操作系统上默认的java环境是java6,没有发送和接收指定源组播的接口,接收指定源组播是通过setsockopt系统调用来实现的,java下可以通过jni来实现这个功能

c部分代码如下

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/udp.h>

unsigned short csum(unsigned short *buf, int nwords)
{
	unsigned long sum;
	for (sum=0; nwords>0; nwords--)
	{
		sum += *buf++;
	}

	sum = (sum >> 16) + (sum &0xffff);
	sum += (sum >> 16);
	return (unsigned short) (~sum);
}

int send_udp_with_mtu(int sock_raw, char *buf, unsigned short len, char *src, unsigned short src_port, char *dst, unsigned short dst_port)
{
	static unsigned short id = 0;
	static unsigned mtu = 16;
	char tmp[1024] = {0};
	struct iphdr *ip = (struct iphdr *)tmp;
	struct udphdr *udp = (struct udphdr *)(tmp + sizeof(struct iphdr));

	id++;

	ip->ihl = 5;
	ip->version = 4;
	ip->tos = 16;
	ip->id = id;
	ip->protocol = 17;
	ip->saddr = inet_addr(src);
	ip->daddr = inet_addr(dst);

	udp->source = htons(src_port);
	udp->dest = htons(dst_port);
	udp->len = htons(len + sizeof(struct udphdr));

	ip->check = 0;

	if (mtu - sizeof(struct udphdr) < len)
	{
		memcpy(tmp + sizeof(struct iphdr) + sizeof(struct udphdr), buf, mtu - sizeof(struct udphdr));
		ip->tot_len = htons(sizeof(struct iphdr) + mtu);
		ip->frag_off = htons(0x2000);
	}
	else
	{
		ip->frag_off = htons(0);
		memcpy(tmp + sizeof(struct iphdr) + sizeof(struct udphdr), buf, len);
		ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + len);
	}

	struct sockaddr_in sin = {
		.sin_family = AF_INET,
		.sin_port = htons(dst_port),
		.sin_addr.s_addr = inet_addr(dst)
	};
	if (-1 == sendto(sock_raw, tmp, ntohs(ip->tot_len), 0, (struct sockaddr *)&sin, sizeof(sin)))
	{
		perror("send1");
		return -1;
	}

	for (int i=mtu-sizeof(struct udphdr); i<len; i+=mtu)
	{
		unsigned short offset = (i + sizeof(struct udphdr));
		if (offset + mtu > len)
		{
			ip->frag_off = htons(offset/8);
			ip->tot_len = htons(sizeof(struct iphdr) + len - i);
		}
		else
		{
			ip->frag_off = htons(offset/8 | 0x2000);
			ip->tot_len = htons(sizeof(struct iphdr) + mtu);
		}
		memcpy(tmp + 20, buf + i, ntohs(ip->tot_len) - sizeof(struct iphdr));
		ip->check = 0;
		ip->id = id;
		
		if (-1 == sendto(sock_raw, tmp, ntohs(ip->tot_len), 0, (struct sockaddr *)&sin, sizeof(sin)))
		{
			perror("send2");
			return -1;
		}
	}


	return 0;
}

int main()
{
	int fd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
	if (fd == -1)
	{
		perror("raw socket");
		return -1;
	}

	int one = 1;
	if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) == -1)
	{
		perror("setsockopt");
		close(fd);
		return -1;
	}

	char *buf = "adcdefggehijklmnbghggxxxy";
	send_udp_with_mtu(fd, buf, strlen(buf), "192.168.66.128", 7777, "232.1.1.1", 8888);
	close(fd);
}

jni代码如下

#include "UdpWithRaw.h"

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/ip.h>
#include <linux/udp.h>

unsigned short csum(unsigned short *buf, int nwords)
{
	unsigned long sum;
	for (sum=0; nwords>0; nwords--)
	{
		sum += *buf++;
	}

	sum = (sum >> 16) + (sum &0xffff);
	sum += (sum >> 16);
	return (unsigned short) (~sum);
}

int send_udp_with_mtu(int sock_raw, char *buf, unsigned short len, char *src, unsigned short src_port, char *dst, unsigned short dst_port)
{
	if (sock_raw <=0 || !buf || len<=0 || !src || src_port<=0 || !dst || dst_port<=0)
	{
		return -1;
	}

	static unsigned short id = 0;
	static unsigned mtu = 512;
	char tmp[1024] = {0};
	struct iphdr *ip = (struct iphdr *)tmp;
	struct udphdr *udp = (struct udphdr *)(tmp + sizeof(struct iphdr));

	id++;

	ip->ihl = 5;
	ip->version = 4;
	ip->tos = 16;
	ip->id = id;
	ip->protocol = 17;
	ip->saddr = inet_addr(src);
	ip->daddr = inet_addr(dst);

	udp->source = htons(src_port);
	udp->dest = htons(dst_port);
	udp->len = htons(len + sizeof(struct udphdr));

	ip->check = 0;

	if (mtu - sizeof(struct udphdr) < len)
	{
		memcpy(tmp + sizeof(struct iphdr) + sizeof(struct udphdr), buf, mtu - sizeof(struct udphdr));
		ip->tot_len = htons(sizeof(struct iphdr) + mtu);
		ip->frag_off = htons(0x2000);
	}
	else
	{
		ip->frag_off = htons(0);
		memcpy(tmp + sizeof(struct iphdr) + sizeof(struct udphdr), buf, len);
		ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + len);
	}

	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(dst_port);
	sin.sin_addr.s_addr = inet_addr(dst);

	if (-1 == sendto(sock_raw, tmp, ntohs(ip->tot_len), 0, (struct sockaddr *)&sin, sizeof(sin)))
	{
		perror("send1");
		return -1;
	}

	for (int i=mtu-sizeof(struct udphdr); i<len; i+=mtu)
	{
		unsigned short offset = (i + sizeof(struct udphdr));
		if (offset + mtu > len)
		{
			ip->frag_off = htons(offset/8);
			ip->tot_len = htons(sizeof(struct iphdr) + len - i);
		}
		else
		{
			ip->frag_off = htons(offset/8 | 0x2000);
			ip->tot_len = htons(sizeof(struct iphdr) + mtu);
		}
		memcpy(tmp + 20, buf + i, ntohs(ip->tot_len) - sizeof(struct iphdr));
		ip->check = 0;
		ip->id = id;
		
		if (-1 == sendto(sock_raw, tmp, ntohs(ip->tot_len), 0, (struct sockaddr *)&sin, sizeof(sin)))
		{
			perror("send2");
			return -1;
		}
	}


	return 0;
}

int create_socket_raw()
{
	int fd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
        if (fd == -1)
        {
                perror("raw socket");
                return -1;
        }

        int one = 1;
        if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) == -1)
        {
                perror("setsockopt");
                close(fd);
                return -1;
        }

	return fd;
}


JNIEXPORT jint JNICALL Java_UdpWithRaw_createRawSock
  (JNIEnv *env, jobject jo)
{
	return (jint)create_socket_raw();
}

JNIEXPORT jint JNICALL Java_UdpWithRaw_closeRawSock
  (JNIEnv *env, jobject jo, jint fd)
{
	if ((int) fd <= 0)
	{
		return (jint) -1;
	}

	close((int) fd);
	return (jint) 0;
}

JNIEXPORT jint JNICALL Java_UdpWithRaw_sentWithMtu
  (JNIEnv *env, jobject jo, jint fd, jbyteArray buf, jstring src, jint src_port, jstring dst, jint dst_port)
{
	if ((int)fd <= 0)
	{
		return (jint)-1;
	}

	const char *src_c = env->GetStringUTFChars(src, 0);
	const char *dst_c = env->GetStringUTFChars(dst, 0);
	
	const int len = env->GetArrayLength(buf);
	jbyte *buf_c = env->GetByteArrayElements(buf, NULL);

//int send_udp_with_mtu(int sock_raw, char *buf, unsigned short len, char *src, unsigned short src_port, char *dst, unsigned short dst_port)
	int r = send_udp_with_mtu((int)fd, (char *)buf_c, (unsigned short)len, (char *)src_c, (int) src_port, (char *)dst_c, (int)dst_port);

	env->ReleaseStringUTFChars(src, src_c);
	env->ReleaseStringUTFChars(dst, dst_c);
	env->ReleaseByteArrayElements(buf, buf_c, 0);

	if (r == 0)
	{
		return (jint) 0;
	}
	else
	{
		return (jint) -1;
	}
}


测试代码如下

public class UdpWithRaw
{
	static {
		System.loadLibrary("UdpWithRawNative");
	}
	public native int createRawSock();
	public native int closeRawSock(int fd);
	public native int sentWithMtu(int fd, byte[] buf, String src, int src_port, String dst, int dst_port);

	public static void main(String[] args)
	{
		System.out.println("hello world");
		UdpWithRaw udp = new UdpWithRaw();
		int fd = udp.createRawSock();
		System.out.println(fd);
		byte[] buf = new byte[1024];
		buf[0] = 'a';
		System.out.println(udp.sentWithMtu(fd, buf, "192.168.66.128", 7777, "232.1.1.1", 8888));
		System.out.println(udp.closeRawSock(fd));
	}
}

参考源码gitee

参考源码github

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值