7-8作业

该代码示例展示了网络通信中的广播、组播以及多进程模型的应用。广播端向特定IP的特定端口发送信息,接收端在同一IP和端口接收。组播中,发送端向组播地址发送消息,接收端加入组播并接收信息。多进程模型用于处理客户端连接,每个连接由子进程处理,父进程负责接收新的连接请求。此外,还包括了简单的文件上传和下载功能,使用UDP协议进行数据交换。
摘要由CSDN通过智能技术生成

1.广播
发送端

#include <myhead.h>
 
#define ERR_MSG(msg) do{\
	fprintf(stderr, "__%d__\n", __LINE__);\
	perror("msg");\
}while(0)
 
#define IP "192.168.123.255"
#define PORT 8888
 
int main(int argc, const char *argv[])
{
	//创建套接字
	int sfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
 
 
 
	//设置允许广播
	int broad = 1;
	if (setsockopt(sfd, SOL_SOCKET, SO_BROADCAST, (void *)&broad, sizeof(broad)) < 0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
 
 
 
	//存储接收方信息
	struct sockaddr_in sin;
	sin.sin_family      = AF_INET;
	sin.sin_addr.s_addr = inet_addr(IP);
	sin.sin_port        = htons(PORT);
 
 
 
	char buf[128] = "";
	//发送信息
	while(1)
	{
		bzero(buf, sizeof(buf));
 
		fgets(buf, sizeof(buf), stdin);
		buf[strlen(buf) - 1] = '\0';
 
		if (sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
			return -1;
		}
	}
 
	close(sfd);
 
	return 0;
}

接收端

#include <myhead.h>
 
#define ERR_MSG(msg) do{\
	fprintf(stderr, "__%d__\n", __LINE__);\
	perror("msg");\
}while(0)
 
#define IP "192.168.123.255"
#define PORT 8888
 
int main(int argc, const char *argv[])
{
	//创建套接字
	int sfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
 
 
 
	//绑定发送方信息
	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)
	{
		ERR_MSG("bind");
		return -1;
	}
 
 
 
	char buf[128] = "";
	//接收信息
	while(1)
	{
		bzero(buf, sizeof(buf));
 
		if (recvfrom(sfd, buf, sizeof(buf), 0, NULL, NULL) < 0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		printf(": %s\n", buf);
	}
 
	close(sfd);
 
	return 0;
}

2.组播
2.1发送端

#include <myhead.h>
 
#define ERR_MSG(msg) do{\
	fprintf(stderr, "__%d__\n", __LINE__);\
	perror("msg");\
}while(0)
 
#define IP "224.10.2.3"
#define PORT 6666
 
int main(int argc, const char *argv[])
{
	//创建套接字
	int sfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
 
 
 
	//存储接收方信息
	struct sockaddr_in sin;
	sin.sin_family      = AF_INET;
	sin.sin_port        = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
 
 
 
	char buf[128] = "";
	while(1)
	{
		bzero(buf,sizeof(buf));
		fgets(buf, sizeof(buf), stdin);
		buf[strlen(buf) - 1] = '\0';
		//发送信息
		if (sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		printf("发送成功\n");
	}
 
	close(sfd);
	
	return 0;
}

2.2接收端

#include <myhead.h>
 
#define ERR_MSG(msg) do{\
	fprintf(stderr, "__%d__\n", __LINE__);\
	perror("msg");\
}while(0)
 
#define zb_IP "224.1.2.3"
#define loc_IP "192.168.122.221"
#define PORT 8888
 
int main(int argc, const char *argv[])
{
	//创建套接字
	int sfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
 
 
 
	//设置组播
	struct ip_mreqn mq;
	mq.imr_multiaddr.s_addr = inet_addr(zb_IP);
	mq.imr_address.s_addr   = inet_addr(loc_IP);
	mq.imr_ifindex          = 2;	
	if (setsockopt(sfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mq, sizeof(mq)) < 0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
 
 
 
 
	//存储发送方信息
	struct sockaddr_in sin;
	sin.sin_family      = AF_INET;
	sin.sin_port        = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(loc_IP);
 
 
 
	char buf[128] = "";
	while(1)
	{
		//接收信息
		if (recvfrom(sfd, buf, sizeof(buf), 0, NULL, NULL) < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
	
	}
 
	close(sfd);
	
	return 0;
}

3.多进程模型


#include <myhead.h>
 
#define ERR_MSG(msg) do{\
	fprintf(stderr, "__%d__\n", __LINE__);\
	perror("msg");\
}while(0)
 
#define IP "192.168.122.221"
#define PORT 6666
 
int deal_cli_msg(int newfd, struct sockaddr_in cin);
 
void handler(int sig)
{
	while(waitpid(-1, NULL, WNOHANG) > 0);
}
 
int main(int argc, const char *argv[])
{
	//绑定17号信号
	if (signal(SIGCHLD, handler) == SIG_ERR)
	{
		ERR_MSG("signal");
		return -1;
	}
 
 
 
	//获取套接字
	int sfd = socket(AF_INET, SOCK_STREAM, 0);
 
	if (sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket success\n");
 
 
 
	//设置端口快速重用
	int rouse = 1;
	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &rouse, sizeof(rouse)) < 0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	printf("setpost success\n");
 
 
 
	//绑定服务器信息
	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)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success\n");
 
 
	//设置被动监听
	if (listen(sfd, 128) < 0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success\n");
 
 
 
	//存储发送方信息
	struct sockaddr_in cin;
	socklen_t address = sizeof(cin);
	pid_t pid = 0;
	int newfd = -1;
 
 
 
	while(1)
	{
		//等待客户端连接
		newfd = accept(sfd, (struct sockaddr *)&cin, &address);
 
		if (newfd < 0)
		{
			ERR_MSG("accept");
			return -1;
		}
		printf("accept success\n");
		
 
 
		//创建子进程用于接发信息
		pid = fork();
		if (0 == pid)
		{
			close(sfd);
 
			deal_cli_msg(newfd,cin);
 
			close(newfd);
 
			exit(0);
		}
 
		close(newfd);
 
		waitpid(-1, NULL, WNOHANG);
 
	}
 
	close(sfd);
 
	return 0;
}
 
 
 
int deal_cli_msg(int newfd, struct sockaddr_in cin)
{
	ssize_t res = 0;
	char buf[128] = "";
 
	while (1)
	{
		bzero(buf, sizeof(buf));
		//接收信息
 
		res = recv(newfd, buf, sizeof(buf), 0);
 
		if (res < 0)
		{
			ERR_MSG("recv");
			return -1;
		}
 
		else if (res == 0)
		{
			printf("[%s : %d] :offline\n",\
					inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));	
			break;
		}
 
		else
			printf("[%s : %d] : %s\n",\
					inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);
 
 
		strcat(buf,"*_*");	
		//发送信息
		if (send(newfd, buf, sizeof(buf), 0) < 0)
		{
			ERR_MSG("send");
			return -1;
		}
		printf("send success\n");
 
	}
 
	return 0;
}

4.上传下载

#include <myhead.h>
 
#define ERR_MSG(msg) do{\
	fprintf(stderr, "line:%d\n", __LINE__);\
	perror(msg);\
}while(0)
 
#define IP "192.168.122.111"
#define PORT 69
 
int do_download(int cfd,struct sockaddr_in sin);
 
int do_upload(int cfd, struct sockaddr_in sin);
 
int main(int argc, const char *argv[])
{
   //创建报式套接字
	int cfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (cfd < 0)
	{
		ERR_MSG("socket");	
		return -1;
	}
	printf("cfd = %d\n", cfd);
 
 
 
   //填充服务器的地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family      = AF_INET;        
	sin.sin_port        = htons(PORT);   
	sin.sin_addr.s_addr = inet_addr(IP);   
	
	
	
	char c = 0;
	while (1)
	{
 
		printf("请选择:\n\t 1>下载\n\t 2>上传\n\t 3>退出\n");
 
		c = getchar();
		while (getchar() != 10)
 
		printf("%c\n",c);
		switch (c)
		{
			case '1':
				do_download(cfd, sin);
				break;
			case '2':
				 do_upload(cfd, sin);
				break;
			case '3':
				goto END;
			default:
				printf("输入错误,请重新输入:\n");
		}
 
	}
 
 
 
END:
	//关闭文件描述符
	close(cfd);
 
	return 0;
}
int do_download(int cfd,struct sockaddr_in sin)
{
   	char name[20] = "";
	printf("请输入文件名:");
	scanf("%s", name);
	while(getchar() != 10);
 
 
 
	//组数据包
	char buf[516] = "";
 
	unsigned short *ptr1 = (unsigned short *)buf;
	*ptr1 = htons(1);
 
	char *ptr2 = buf + 2;
	strcpy(ptr2, name);
 
	char *ptr3 = ptr2 + strlen(name);
	*ptr3 = 0;
 
	char *ptr4 = ptr3 + 1;
	strcpy(ptr4, "octet");
 
	int size = 2 + 2 + 1 + strlen(ptr2) + strlen(ptr4);
 
 
 
    //发送下载请求给服务器
	if (sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("sendto 下载请求");
		return -1;
	}
	printf("发送下载请求给服务器成功\n");
 
 
 
    //打开一个用于写入的文件
    int fd = open(ptr2, O_WRONLY|O_CREAT|O_APPEND, 0664);
    if(fd < 0)
	{
        ERR_MSG("fd err");
		return -1;
	}
 
 
 
    while(1)
	{
		bzero(buf, sizeof(buf));
		socklen_t addlen = sizeof(sin);
		int res = 0;
		if((res = recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &addlen)) < -1)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
 
 
 
		//写入本地
		char *data = buf + 4;
		write(fd, data, 512);
 
 
 
		//组ACK包
		unsigned short net = *(ptr1 + 1);
		bzero(buf, sizeof(buf));
		*ptr1 = htons(4);
		*(ptr1 + 1) = net;
 
 
 
		//回复ACK
		if(sendto(cfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
		{
			ERR_MSG("sendto");
			return -1;
		}
 
 
 
		//判断数据是否小于512,若小于512,则传输结束
		if(res<516)
			break;
 
	}
 
    close(fd);
    return -1;
}
 
 
 
int do_upload(int cfd, struct sockaddr_in sin)
{
    char name[20] = "";
	printf("请输入文件名:");
	scanf("%s", name);
	while(getchar() != 10);
 
 
 
    //组数据包
	char buf[516] = "";
 
	unsigned short *ptr1 = (unsigned short *)buf;
	*ptr1 = htons(2);
 
	char *ptr2 = buf + 2;
	strcpy(ptr2, name);
 
	char *ptr3 = ptr2 + strlen(name);
	*ptr3 = 0;
 
	char *ptr4 = ptr3 + 1;
	strcpy(ptr4, "octet");
 
	int size = 2 + 2 + 1 + strlen(ptr2) + strlen(ptr4);
 
 
 
    //发送上传请求给服务器
	if (sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("sendto 上传请求");
		return -1;
	}
	printf("发送上传请求给服务器成功\n");
 
 
 
    // 获取服务器的临时端口
    struct sockaddr_in tem_sin;
    socklen_t addrlen = sizeof(tem_sin);
 
 
 
    // 接收服务器发来的包
    bzero(buf, sizeof(buf));
    if (recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&tem_sin, &addrlen) < 0) 
	{
        ERR_MSG("recvfrom error");
    }
 
 
 
    // 打开上传的文件
	int fd = open("./1.c", O_RDONLY);
    if (fd < 0) 
	{
        ERR_MSG("open error");
        return -1;
    }
 
 
 
    while (1) 
	{
		unsigned short net = *(ptr1 + 1);
        bzero(buf, sizeof(buf));
        // 组数据包
		*ptr1 = htons(3);
		*(ptr1 + 1) = net;
 
 
 
		int res = 0;
        // 发送数据包
        res = sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&tem_sin, sizeof(tem_sin));
        if (res < 0) 
		{
            ERR_MSG("sendto error");
            return -1;
        }
 
 
 
		//判断数据是否小于512,若小于512,则传输结束
		if(res<516)
			break;
 
 
 
        // 接收并检验服务器发来的包
        bzero(buf, sizeof(buf));
        if (recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&tem_sin, &addrlen) < 0) 
		{
            ERR_MSG("recvfrom error");
            return -1;
        }
    }
    return 0;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值