网络编程-day4 作业

上交select服务器客户端代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>

#define ERR_MSG(msg) do{\
	printf("line:%d\n",__LINE__);\
	perror(msg);\
}while(0)
 
#define PORT 1234
#define IP  "192.168.10.224" 
int main(int argc, const char *argv[])
{ 
	//创建套接字
	int cfd=socket(AF_INET,SOCK_STREAM,0);
	if(cfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket create success cfd=%d __%d__\n",cfd,__LINE__);
	struct sockaddr_in sin;
	sin.sin_family 		=AF_INET;
	sin.sin_port  		=htons(PORT);
	sin.sin_addr.s_addr =inet_addr(IP);
	fd_set readfds,tempfds;
	FD_ZERO(&readfds);
	FD_ZERO(&tempfds);
	FD_SET(0,&readfds);
	FD_SET(cfd,&readfds);

	//connect
	if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("connect");
		return -1;
	}
	printf("connect success\n");
 
	char buf[128]="";
	ssize_t res=0;
	int s_res=0;
	while(1)
	{
		tempfds=readfds;
		s_res=select(cfd+1,&tempfds,NULL,NULL,NULL);
		if(s_res<0)
		{
			ERR_MSG("select");
			return -1;
		}
		else if(0==s_res)
		{
			printf("time out!\n");
			return -1;
		}
		if(FD_ISSET(0,&tempfds))
		{
			bzero(buf,sizeof(buf));
			printf("请输入:");
			scanf("%s",buf);
			//send
			if(send(cfd,buf,sizeof(buf),0)<0)
			{
				ERR_MSG("send");
				return -1;
			}
			printf("send success\n");
		}
 		if(FD_ISSET(cfd,&tempfds))
		{
		//recv
		bzero(buf,sizeof(buf));
		res=recv(cfd,buf,sizeof(buf),0);
		if(res<0)
		{
			ERR_MSG("recv");
			return -1;
		}
		else if(0==res)
		{
			printf("服务端下线\n");
			break;
		}
		printf("__%d__\t接收信息: %s\n",__LINE__,buf);
		}
	}
	
	//关闭文件描述符
	if(close(cfd)<0)
	{
		ERR_MSG("close");
		return -1;
	}
	return 0;
}

poll代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>

#define ERR_MSG(msg) do{\
    printf("line: %d\n", __LINE__); \
    perror(msg);\
}while(0)

#define PORT 1234   //端口号的网络字节序 1024~49151
#define IP "192.168.10.224" //ifconfig查看本机IP

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

    //功能:允许端口快速被重用,快速被复用
    int reuse =1;
    if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }

    //绑定,客户端非必须绑定,
    //如果不绑定则程序启动后操作系统会默认绑定一个可用IP和随机端口
    //填充服务器的地址信息结构体,给conncet函数使用
    //连接哪个服务器,就填哪个服务器的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(IP);    //ifconfig查看本机IP

    //连接到服务器
    if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("connect");
        return -1;
    }
    printf("服务器连接成功 __%d__\n", __LINE__);

    //创建集合
    struct pollfd fds[2];

    fds[0].fd = 0;              //指定要监测0号
    fds[0].events = POLLIN;     //监测0号文件描述符对应的空间中是否有数据可读

    fds[1].fd = cfd;
    fds[1].events = POLLIN;


    char buf[128] = "";
    ssize_t res = 0;
    int p_res = 0;
    while(1)
    {
        //阻塞方式监测集合
        p_res = poll(fds, 2, -1);
        if(p_res < 0)
        {
            ERR_MSG("poll");
            return -1;
        }
        else if(0 == p_res)
        {
            printf("time out...\n");
            break;
        }
        //判断0号文件描述符是否有POLLIN事件
        if((fds[0].revents & POLLIN) != 0)
        {
            fgets(buf, sizeof(buf), stdin);
            buf[strlen(buf)-1] = 0;

            if(send(cfd, buf, sizeof(buf), 0) < 0)
            {
                ERR_MSG("send");
                return -1;
            }
            printf("发送成功\n");
        }

        //cfd文件描述符有POLLIN事件
        if(fds[1].revents & POLLIN)
        {
            bzero(buf, sizeof(buf));
            //接收数据
            res = recv(cfd, buf, sizeof(buf), 0);
            if(res < 0)
            {
                ERR_MSG("recv");
                return -1;
            }
            else if(0 == res)
            {
                printf("[%s:%d] 服务器下线 __%d__\n",\
                        inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), __LINE__);
                break;
            }

            printf("[%s:%d] cfd=%d : %s, __%d__\n",\
                    inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), cfd, buf, __LINE__);

        }

    }


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


    return 0;
}

tftp服务器上传下载

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>

#define ERR_MSG(msg) do{\
	printf("line=%d\n",__LINE__);\
	perror(msg);\
}while(0)
#define PORT 69
#define IP "192.168.10.139"
int download(int sfd,struct sockaddr_in sin);
int upload(int sfd,struct sockaddr_in sin);
int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket creat success line = %d\n",__LINE__);
	//填充服务器自身的地址信息结构体
	//真实的地址信息结构体根据地址族制定 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(IP);// 填充本机IP
	int mode=0;
	while(1)
	{
		printf("please input-->");
		scanf("%d",&mode);
		if(mode==1)
		{
			download(sfd,sin);
		}
		else if(mode==2)
		{
			upload(sfd,sin);
		}
	}
	return 0;
}
int upload(int sfd,struct sockaddr_in sin)
{
	char buf[516] = "";
	*(short*)buf = htons(2);     //操作码1读 2写
	char *ptr1 = buf + 2;       //文件名
	printf("请输入上传的文件名>>>");
	char name[128] = "";
	scanf("%s", name);
	strcpy(ptr1, name);
	char *ptr2 = buf + strlen(ptr1) + 3;   //模式
	strcpy(ptr2, "octet");
	int buflen = 2 + strlen(ptr1) + 1 + strlen(ptr2) + 1;
	if(sendto(sfd, buf, buflen, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("sendto");
		return -1;
	}
	//收发数据包
	struct sockaddr_in recvaddr;
	socklen_t addrlen = sizeof(recvaddr);
	short opflag = 0;
	short req_num = 0;  //对方需要的块编号
	short snd_num = 0;  //己方发送的块编号
	ssize_t res = 0;
	int fd = open(name, O_RDONLY);
	if(fd < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	//发送上传请求后,对面会回答一个ACK(0)
	while(1)
	{
		//接受应答信息
		bzero(buf, sizeof(buf));
		res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&recvaddr, &addrlen);
		if(res < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
		opflag = ntohs(*(short*)buf);
		req_num  = ntohs(*(short*)(buf+2));

		if(4==opflag && req_num==snd_num)
		{
			//发送数据包
			bzero(buf, sizeof(buf));
			*(short*)buf = htons(3);
			*(short*)(buf+2) = htons(++snd_num);
			res = read(fd, buf+4, sizeof(buf)-4);
			if(res < 0)
			{
				ERR_MSG("read");
				return -1;
			}
			else if(res == 0)
			{
				break;
			}
			if(sendto(sfd, buf, res+4, 0, (struct sockaddr*)&recvaddr, addrlen) < 0)
			{
				ERR_MSG("sendto");
				return -1;
			}
		}
		else
		{
			printf("error__%d__\n", __LINE__);
			return -1;
		}
	}

	if(close(fd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("上传成功\n");

}
int download(int sfd,struct sockaddr_in sin)
{
	//组下载协议
	char buf[516]="";
	int n;
	short int* ptr=(short int *)buf;
	*ptr=htons(1);
	char *ptr2=buf+2;
	//strcpy(ptr2,"1_armcli.c");
	strcpy(ptr2,"5.png");  //定义要下载的文件
	char *ptr3 = ptr2+strlen(ptr2)+1;
	strcpy(ptr3,"octet");
	int size=2+strlen(ptr2)+1+strlen(ptr3)+1;
	if(sendto(sfd,buf,size,0,(struct sockaddr *)&sin,sizeof(sin))<0) //向服务器发送下载协议
	{
		ERR_MSG("sendto");
		return -1;
	}
	struct sockaddr_in fake_sin; //定义一个地址结构体变量来接受服务器的IP和临时端口信息
	int len=sizeof(fake_sin);
	int fd_w=open("./copy.png",O_WRONLY|O_CREAT|O_TRUNC,0664);   //将要写入的文件打开
	if(fd_w<0)
	{
		printf("error __%d__\n",__LINE__);
		return -1;
	}
	short int i=0;
	int flag=0;
	while (1)
	{
		bzero(buf,sizeof(buf));    //每次循环前将数组清零
		//判断每次收到的字节数是否等于516,如果小于516则说明是最后一个数据包,将flag置1
		//最后写入一次然后退出循环
		if((n=recvfrom(sfd,buf,516,0,(struct sockaddr*)&fake_sin,&len))<516)
			flag = 1;
		char* ptr4=buf+4;//buf数组前四个字节不属于要写入的数据,直接跳过
		int len_buf=n-4; //写入的真实长度
		if(write(fd_w,ptr4,len_buf)<0)
		{
			ERR_MSG("write");
			return -1;
		}
		printf("写入ing\n");
		short int ack[2];  //定义一个数组来存储应答信号
		short int* ptr5 = (short int*)buf;  //用同为两个字节short类型去获取操作码
		i = ntohs(*ptr5);  //将获取到的操作码由网络字节序转为本机字节序
		i++;      //操作码自加1
		*ptr5 = htons(i);  //将自加后的操作码再次转为网络字节序存储到ptr5中
		short int* ptr6 = ptr5 + 1;  //用ptr6获取buf中存储的块编号
		ack[0] = *ptr5;
		ack[1] = *ptr6; //拼接应答信号
		if (sendto(sfd, ack, sizeof(ack), 0, (struct sockaddr*)&fake_sin, sizeof(fake_sin)) < 0)
		{
			ERR_MSG("sendto");
			return -1;
		}
		printf("应答\n");
		// 如果接收到的数据小于512字节,并且本次接收已经不是完整的512字节,
		// 则为最后一包数据,直接退出循环
		if (flag == 1 && len_buf < 516 - 4)
			break;
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值