7.7 作业

1. 广播,组播代码重新写一遍

#include <myhead.h>
#define IP "192.168.123.255"
int main(int argc,const char *argv[])
{
	int sfd = socket(AF_INET,SOCK_DGRAM,0);//获取套接字文件
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

	int opt = 1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0)//允许端口快速重用	
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	
	if(setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)) < 0)//允许广播
	{
		ERR_MSG("setsockopt");
		return -1;
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8888);//设置接受方端口
	addr.sin_addr.s_addr = inet_addr(IP);	//设置广播ip
	while(1)
	{
		char a[20]="";
		printf("输入内容:");
		scanf("%s",a);
		sendto(sfd,a,sizeof(a),0,(struct sockaddr *)&addr,sizeof(addr));//发送数据
	}

	close(sfd);
	return 0;
}
#include <myhead.h>
#define IP "192.168.123.255"
int main(int argc,const char *argv[])
{
	int sfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字文件
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

	int opt = 1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0)//允许端口快速重用	
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8888);//设置绑定的端口
	addr.sin_addr.s_addr = inet_addr(IP);//设置广播ip
	socklen_t addrlen = sizeof(addr);
	if(bind(sfd,(struct sockaddr *)&addr,sizeof(addr)))//绑定端口和ip
	{
		ERR_MSG("bind");
		return -1;
	}
	puts("bind success");
	
	while(1)
	{
		char a[128]="";	
		struct sockaddr_in fs;
		socklen_t fslen = sizeof(fs);
		recvfrom(sfd,a,sizeof(a),0,(struct sockaddr *)&fs,&fslen);//接受数据,并获得发送方的ip和端口
		printf("[%s:%d] %s\n",inet_ntoa(fs.sin_addr),ntohs(fs.sin_port),a);
	}

	close(sfd);
	return 0;
}

 

#include <myhead.h>
#define IP "224.1.2.3"
int main(int argc,const char *argv[])
{
	int sfd = socket(AF_INET,SOCK_DGRAM,0);//设置套接字文件
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

	int opt = 1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0)//设置端口被快速重用	
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8888);//设置端口
	addr.sin_addr.s_addr = inet_addr(IP);//设置组播ip
	while(1)
	{
		char a[128]="";
		printf("输入内容:");
		fgets(a,sizeof(a),stdin);
		a[strlen(a)-1] = '\0';
		sendto(sfd,a,sizeof(a),0,(struct sockaddr *)&addr,sizeof(addr));//发送数据
	}

	close(sfd);
	return 0;
}
#include <myhead.h>
#define IP "224.1.2.3"
int main(int argc,const char *argv[])
{
	int sfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字文件
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

	int opt = 1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0)//允许端口被快速重用	
	{
		ERR_MSG("setsockopt");
		return -1;
	}

	struct ip_mreqn ipopt;
	ipopt.imr_multiaddr.s_addr = inet_addr(IP);//设置组播ip
	ipopt.imr_address.s_addr = inet_addr("192.168.122.183");//设置本地ip
	ipopt.imr_ifindex = 0;//设置网卡设备号
	if(setsockopt(sfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&ipopt,sizeof(ipopt)) < 0)//设置加入组播
	{
		ERR_MSG("setsockopt");
		return -1;
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8888);//设置端口
	addr.sin_addr.s_addr = inet_addr(IP);//组播ip
	socklen_t addrlen = sizeof(addr);
	if(bind(sfd,(struct sockaddr *)&addr,sizeof(addr)))//绑定ip和端口
	{
		ERR_MSG("bind");
		return -1;
	}
	puts("bind success");
	
	while(1)
	{
		char a[128]="";	
		struct sockaddr_in fs;
		socklen_t fslen = sizeof(fs);
		recvfrom(sfd,a,sizeof(a),0,(struct sockaddr *)&fs,&fslen);//接收数据
		printf("[%s:%d] %s\n",inet_ntoa(fs.sin_addr),ntohs(fs.sin_port),a);
	}

	close(sfd);
	return 0;
}

 

2. 多进程通过模型自己写一遍

#include <myhead.h>
#define ERR_MSG(msg) fprintf(stderr,"%d\n",__LINE__);perror(msg);
#define IP "192.168.122.183"
int delclimsg(int newfd,const struct sockaddr_in *addr)
{	
	while(1)
	{
		char buf[128] = "";
		ssize_t res = recv(newfd,buf,sizeof(buf),0);//读取信息
		if(res < 0)
		{
			ERR_MSG("recv");
			return -1;
		}
		else if(res == 0)
		{
			printf("[%s:%d] 客户端:%d 下线\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),newfd);
			break;
		}
		printf("[%s:%d] 客户端:%d 的消息:%s\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),newfd,buf);

		res = send(newfd,buf,sizeof(buf),0);//发送信息
		if(res < 0)
		{
			ERR_MSG("send");
			return -1;
		}
	}
}
void signal_hadler(int signo)//回收子进程资源
{
	while(waitpid(-1,NULL,WNOHANG) > 0);
}

int main(int argc,const char *argv[])
{
	int sfd = socket(AF_INET,SOCK_STREAM,0);//创建套接子文件
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

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

	struct sockaddr_in sai;
	sai.sin_family = AF_INET;//协议族
	sai.sin_port = htons(6666);//服务器端口
	sai.sin_addr.s_addr = inet_addr(IP);//服务器IP
	if(bind(sfd,(struct sockaddr *)&sai,sizeof(struct sockaddr_in)) < 0)//绑定ip和端口
	{
		ERR_MSG("bind");
		return -1;
	}
	puts("bind success");

	if(listen(sfd,128) < 0)//设置为被动监听状态,最大128
	{
		ERR_MSG("listen");
		return -1;
	}
	puts("listen success");

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

	signal(SIGCHLD,signal_hadler);//当子进程死亡时捕获信号

	while(1)
	{
		int newfd = accept(sfd,(struct sockaddr *)&addr,&addrlen);//等待客户端连接,返回客户端的文件描述符和ip端口等
		if(newfd <0)
		{
			ERR_MSG("accept");
			return -1;
		}
		printf("[%s:%d]newfd = %d 客户端连接成功\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port),newfd);

		if(fork()==0)//子进程负责和客户端通信
		{
			close(sfd);
			delclimsg(newfd,&addr);
			close(newfd);
			exit(0);
		}
		close(newfd);
	}

	if(close(sfd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}	
	return 0;
}

3. 多线程代码写一遍,能否将newfd定义成全局(不行,找原因)

#include <myhead.h>
#define ERR_MSG(msg) fprintf(stderr,"%d\n",__LINE__);perror(msg);
#define IP "192.168.122.183"
typedef struct{
	int newfd;
	struct sockaddr_in *addr;
}cliin;//定义结构体用于线程传参
void *delclimsg(void *arg)
{
	cliin *cli = arg;
	int newfd = cli->newfd;
	const struct sockaddr_in *addr = cli->addr;	
	while(1)
	{
		char buf[128] = "";
		ssize_t res = recv(newfd,buf,sizeof(buf),0);//读取信息
		if(res < 0)
		{
			ERR_MSG("recv");
			break;
		}
		else if(res == 0)
		{
			printf("[%s:%d] 客户端:%d 下线\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),newfd);
			break;
		}
		printf("[%s:%d] 客户端:%d 的消息:%s\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),newfd,buf);

		res = send(newfd,buf,sizeof(buf),0);//发送信息
		if(res < 0)
		{
			ERR_MSG("send");
			break;
		}
	}
	close(newfd);
}
int main(int argc,const char *argv[])
{
	int sfd = socket(AF_INET,SOCK_STREAM,0);//创建套接子文件
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

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

	struct sockaddr_in sai;
	sai.sin_family = AF_INET;//协议族
	sai.sin_port = htons(6666);//服务器端口
	sai.sin_addr.s_addr = inet_addr(IP);//服务器IP
	if(bind(sfd,(struct sockaddr *)&sai,sizeof(struct sockaddr_in)) < 0)//绑定ip和端口
	{
		ERR_MSG("bind");
		return -1;
	}
	puts("bind success");

	if(listen(sfd,128) < 0)//设置为被动监听状态,最大128
	{
		ERR_MSG("listen");
		return -1;
	}
	puts("listen success");

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

	while(1)
	{
		int newfd = accept(sfd,(struct sockaddr *)&addr,&addrlen);//等待客户端连接,返回客户端的文件描述符和ip端口等
		if(newfd <0)
		{
			ERR_MSG("accept");
			return -1;
		}
		printf("[%s:%d]newfd = %d 客户端连接成功\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port),newfd);
		
		pthread_t tid;
		cliin cli = {newfd,&addr};
		if(pthread_create(&tid,NULL,delclimsg,&cli) < 0)//创建线程用于进行通信
		{
			fprintf(stderr,"pthread_create error");
			return -1;
		}
		pthread_detach(tid);//线程设置为分离态
	}

	if(close(sfd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}	
	return 0;
}

不能定义为全局变量,后面accept的newfd会覆盖之前的newfd,导致线程无法和之前的客户端进行通信。
4. 上传下载写完。
 

#include <myhead.h>
#define IP "192.168.122.79"
typedef struct{
	uint16_t opcode;
	uint16_t block;
	uint8_t data[512];
}datapag;
typedef struct{
	uint16_t opcode;
	uint16_t block;
}ack;
int upload(int cfd,const struct sockaddr_in *addr,int addrlen)
{
	char fname[20] = "";
	printf("输入文件名:");
	scanf("%s",fname);
	int f = open(fname,O_RDONLY);//打开需要上传的文件
	if(f < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	
	char buf[128]="";//写请求
	char *ptr = buf;
	*(uint16_t *)ptr = htons(2);
	ptr+=2;
	strcpy(ptr,fname);
	ptr += strlen(fname)+1;
	strcpy(ptr,"octet");
	if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr *)addr,addrlen) < 0)//发送请求
	{
		ERR_MSG("sendto");
		return -1;
	}
	
	while(1)
	{
		ack a;
		struct sockaddr_in ser;
		socklen_t serlen = sizeof(ser);
		if(recvfrom(cfd,&a,sizeof(a),0,(struct sockaddr *)&ser,&serlen) < 0)//接受cak
		{
			ERR_MSG("sendto");
			return -1;
		}
		
		datapag dg = {htons(3),htons(ntohs(a.block)+1)};//block加1
		ssize_t len = read(f,dg.data,sizeof(dg.data));//读取512字节的数据放入数据包
		if(len < 0)
		{
			ERR_MSG("read");
			return -1;
		}

		if(sendto(cfd,&dg,len+4,0,(struct sockaddr *)&ser,serlen) < 0)//发送数据包
		{
			ERR_MSG("sendto");
			return -1;
		}

		if(len < sizeof(dg.data))//完成
		{
			break;
		}
	}
	close(f);
}

int download(int cfd,const struct sockaddr_in *addr,int addrlen)
{	//发送数据
	char buf[128]="";
	char *ptr = buf;
	*(uint16_t *)ptr = htons(1);
	ptr += 2;
	char fname[20] = "";
	printf("输入文件名:");
	scanf("%s",fname);
	strcpy(ptr,fname);
	ptr += strlen(fname)+1;
	strcpy(ptr,"octet");
	if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr *)addr,addrlen) < 0)//发送请求
	{
		ERR_MSG("sendto");
		return -1;
	}

	ack a={htons(4),htons(0)};//ack
	int f = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0664);//打开文件往里面放数据
	if(f<0)
	{
		ERR_MSG("open file");
		return -1;
	}
	while(1)
	{
		struct sockaddr_in ser;
		socklen_t serlen = sizeof(ser);
		datapag pg;
		printf("1\n");
		ssize_t len = recvfrom(cfd,&pg,sizeof(pg),0,(struct sockaddr *)&ser,&serlen);//获得数据包和服务器地址
		if (len < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}

		a.block = pg.block;//修改ack的块编号
		printf("2 %d\n",ntohs(a.block));
		if(sendto(cfd,&a,sizeof(a),0,(struct sockaddr *)&ser,serlen) < 0)//发送ack
		{
			ERR_MSG("sendto");
			return -1;
		}

		printf("3 %ld\n",len);
		if(write(f,pg.data,len - 4) < 0)//往文件中写数据
		{
			ERR_MSG("write");
			return -1;
		}
		if(len-4 < 512)//数据不足512则执行结束
		{
			puts("传输完成");
			close(f);
			return 0;
		}
	}
}


int main(int argc,const char *argv[])
{
	//创建套接字
	int cfd = socket(AF_INET,SOCK_DGRAM,0);
	if(cfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	puts("socket success");

	struct sockaddr_in addr;//服务器地址
	addr.sin_family = AF_INET;
	addr.sin_port = htons(69);
	addr.sin_addr.s_addr = inet_addr(IP);
	socklen_t addrlen = sizeof(addr);

	char c = 0;
	while(1)
	{
		puts("1.上传");
		puts("2.下载");
		puts("3.退出");
		c = getchar();
		while(getchar()!='\n');
		if(c=='3')
			break;
		switch(c)
		{
		case '1':
			upload(cfd,&addr,addrlen);//上传函数
			break;
		case '2':
			download(cfd,&addr,addrlen);//下载函数
			break;
		}
	}


	//关闭文件
	close(cfd);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值