组播,广播,多点通信

一、广播

发送方

#include <my_h.h>

#define GRE_IP "192.168.125.205"
#define GRE_PORT 6969

int main(int argc, const char *argv[])
{
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd<0)
	{
		perror("socket");
		return -1;
	}
	printf("创建套接字成功\n");

	int a=1;
	if(setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&a,sizeof(a))<0)
	{
		perror("setsockopt");
		return -1;
	}

	struct sockaddr_in sin;
    sin.sin_family      = AF_INET;
    sin.sin_port        = htons(GRE_PORT);      //接收方绑定的端口号
    sin.sin_addr.s_addr = inet_addr(GRE_IP);    //接收方绑定的IP


    char s[100];
    ssize_t res = 0;
    while(1)
    {
        bzero(s, sizeof(buf));
        printf("请输入>>> ");
        fgets(s, sizeof(s), stdin);
        s[strlen(s)-1] = 0;

        if(sendto(sfd, s, sizeof(s), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
        {
            perror("sendto");
            return -1;
        }
        printf("发送成功\n");

    }
	close(sfd);
	return 0;
}

接收方

#include <my.h_h>

#define PORT 8888
#define IP "192.168.125.205"


int main(int argc, const char *argv[])
{
    //创建报式套接字
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd < 0)
    {
        perror("socket");
        return -1;
    }
    printf("创建成功%d\n", sfd);

    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;          //必须填AF_INET;
    sin.sin_port        = htons(PORT);      //端口号的网络字节序,1024~49151
    sin.sin_addr.s_addr = inet_addr(IP);    //广播IP

    //绑定接收方自身的地址信息
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    {
        perror("bind");
        return -1;
    }
    printf("bind success\n");

    struct sockaddr_in cin;     //存储发送放的地址信息
    socklen_t addrlen =sizeof(cin);

    char s[100];
    ssize_t res = 0;
    while(1)
    {
        bzero(s, sizeof(s));
        //接收数据 --->同时存储这个数据包是从哪里来的,即发送的地址
        res = recvfrom(sfd, s, sizeof(s), 0, (struct sockaddr*)&cin, &addrlen);
        if(res < 0)
        {
            perror("recvfrom");
            return -1;
        }

        printf("[%s:%d] : %s\n", \
                inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), s);
    }

    //关闭套接字
    close(sfd);

    return 0;
}

二、组播

发送方

#include <my.h_h>

#define SER_PORT 8888           //接收方绑定的端口号
#define SER_IP "224.1.2.3"  //组播IP : 224.0.0.0-239.255.255.255


int main(int argc, const char *argv[])
{
    //创建报式套接字
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(cfd < 0)
    {
        perror("socket");
        return -1;
    }
    printf("socket create success cfd=%d\n", cfd);

    //绑定客户端自身的地址信息---》非必须绑定
    //若不绑定则操作系统会给客户端绑定本机IP及随机端口

    //填充地址信息结构体给sendto函数使用,想发给谁就填谁的地址信息
    //真实的地址信息结构体根据地址族指定 AF_INET: man 7 IP
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;              //必须填AF_INET;
    sin.sin_port        = htons(SER_PORT);      //组播端口
    sin.sin_addr.s_addr = inet_addr(SER_IP);    //组播IP

    char s[100];
    ssize_t res = 0;
    while(1)
    {
        bzero(s, sizeof(s));
        printf("请输入>>> ");
        fgets(s, sizeof(s), stdin);
        s[strlen(s)-1] = 0;

        //发送数据, 主动发送给指定接收放,例如这里可以主动发给接收方
        if(sendto(cfd, s, sizeof(s), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
        {
            perror("sendto");
            return -1;
        }
        printf("sendto success\n");
    }

    //关闭套接字
    close(cfd);

    return 0;
}

 接收方

#include <my.h_h>

#define PORT 8888               //端口号的网络字节序,1024~49151
#define GRP_IP "224.1.2.3"          //组播IP 224.0.0.0-239.255.255.255
#define LOL_IP "192.168.125.205"      //ifconfig 的本机IP


int main(int argc, const char *argv[])
{
    //创建报式套接字
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd < 0)
    {
        perror("socket");
        return -1;
    }
    printf("socket create success sfd=%d\n", sfd);

    //加入多播组
    struct ip_mreqn mq;

    mq.imr_multiaddr.s_addr = inet_addr(GRP_IP);    //组播IP
    mq.imr_address.s_addr   = inet_addr(LOL_IP);    //本机IP,ifconfig
    mq.imr_ifindex = 2;         //网络设备索引号

    if(setsockopt(sfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mq, sizeof(mq)) < 0)
    {
        perror("setsockopt");
        return -1;
    }
    printf("加入多播组 [%s] 成功\n", GRP_IP);




    //填充地址信息结构体给bind函数使用
    //真实的地址信息结构体根据地址族指定 AF_INET: man 7 IP
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;          //必须填AF_INET;
    sin.sin_port        = htons(PORT);      //端口号的网络字节序,1024~49151
    sin.sin_addr.s_addr = inet_addr(GRP_IP);    //组播IP 

    //绑定接收方自身的地址信息
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    {
        perror("bind");
        return -1;
    }
    printf("bind success\n");

    struct sockaddr_in cin;     //存储发送放的地址信息
    socklen_t addrlen =sizeof(cin);

    char s[100];
    ssize_t res = 0;
    while(1)
    {
        bzero(s, sizeof(s));
        //接收数据 --->同时存储这个数据包是从哪里来的,即发送的地址
        res = recvfrom(sfd, s, sizeof(s), 0, (struct sockaddr*)&cin, &addrlen);
        if(res < 0)
        {
            perror("recvfrom");
            return -1;
        }

        printf("[%s:%d] : %s\n", \
                inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), s);
    }

    //关闭套接字
    close(sfd);

    return 0;
}

三、TCP

#include <my_h.h>
int s_pid(int newfd,struct sockaddr_in cin);

#define PORT 6888
#define IP "192.168.154.54"

void header(int sig)
{
	while(waitpid(-1,NULL,WNOHANG)<0);
	return ;
}

int main(int argc, const char *argv[])
{
	//回收僵尸进程信号
	if(signal(SIGCHLD,header)==SIG_ERR)
	{
		perror("signal");
		return -1;
	}
	//创建流式套接字
	int sfd=socket(AF_INET,SOCK_STREAM,0);
	if(sfd<-1)
	{
		perror("socket");
		return -1;
	}
	printf("套接字创建成功\n");

	//允许端口快速复用
	int reuse = 1;
	if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		perror("setsockopt");
		return -1;
	}                                                                           
	printf("允许端口快速复用成功\n");

	//创建结构体由bind使用
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(PORT);
	sin.sin_addr.s_addr=inet_addr(IP);

	//绑定地址信息
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)))
	{
		perror("bind");
		return -1;
	}
	printf("绑定成功\n");

	//将上面创建的套接字转换成被动监听状态
	if(listen(sfd,128)<0)
	{
		perror("listen");
		return -1;
	}
	printf("转换状态成功\n");

	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);

	//连接客户端
	while(1)
	{
		int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
		if(newfd<0)
		{
			perror("accept");
			return -1;
		}
		printf("客户端连接成功\n");

		pid_t cpid=fork();
		if(0==cpid)
		{
			s_pid(newfd,cin);
			exit(0);
		}
		else if(cpid<0)
		{
			perror("fork");
			return -1;
		}
		close(newfd);
	}
	close(sfd);
	return 0;
}

int s_pid(int newfd,struct sockaddr_in cin)
{
	char s[100];
	ssize_t res;
	while(1)
	{
		//清空数组
		bzero(s,sizeof(s));
		//接收数据
		res=recv(newfd,s,sizeof(s),0);
		if(res<0)
		{
			perror("recv");
			return -1;
		}
		else if(res==0)
		{
			printf("客户端已下线\n");
			break;
		}
		printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),s);

		if(strcmp(s,"quit")==0)
			break;

		strcat(s,"wow");
		if(send(newfd,s,sizeof(s),0)<0)
		{
			perror("send");
			return -1;
		}
		printf("发送成功\n");
	}
	close(newfd);
	return 0;
}

四、UDP

#include <my_h.h>
#include <pthread.h>

#define PORT 6888
#define IP "192.168.125.205"

void *s_tid(void *arg);
struct s_l
{
	int newfd;
	struct sockaddr_in cin;
};

int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd=socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0)
	{
		perror("socket");
		return -1;
	}
	printf("套接字创建成功\n");

	//允许端口快速复用
	int reuse = 1;
	if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		perror("setsockopt");
		return -1;
	}                                                                           
	printf("允许端口快速复用成功\n");

	//创建结构体由bind使用
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(PORT);
	sin.sin_addr.s_addr=inet_addr(IP);

	//绑定地址信息
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		perror("bind");
		return -1;
	}
	printf("绑定成功\n");

	//将上面创建的套接字转换成被动监听状态
	if(listen(sfd,128)<0)
	{
		perror("listen");
		return -1;
	}
	printf("转换状态成功\n");

	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);

	//连接客户端
	pthread_t tid;
	struct s_l msg;
	while(1)
	{
		int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
		if(newfd<0)
		{
			perror("accept");
			return -1;
		}
		printf("客户端连接成功\n");
		
		msg.newfd=newfd;
		msg.cin=cin;

		if(pthread_create(&tid,NULL,s_tid,(void *)&msg)!=0)
		{
			fprintf(stderr,"创建失败__%d__\n",__LINE__);
			return -1;
		}
		pthread_detach(tid);
	}
	close(sfd);
	return 0;
}

void *s_tid(void *arg)
{
	char s[100];
	ssize_t res;

	int newfd=((struct s_l *)arg)->newfd;
	struct sockaddr_in cin=((struct s_l *)arg)->cin;

	while(1)
	{
		//清空数组
		bzero(s,sizeof(s));
		//接收数据
		res=recv(newfd,s,sizeof(s),0);
		if(res<0)
		{
			perror("recv");
			break;
		}
		else if(res==0)
		{
			printf("客户端已下线\n");
			break;
		}
		printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),s);

		if(strcmp(s,"quit")==0)
			break;

		strcat(s,"wow");
		if(send(newfd,s,sizeof(s),0)<0)
		{
			perror("send");
			break;
		}
		printf("发送成功\n");
	}

	close(newfd);
	pthread_exit(NULL);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值