网络编程(TCP文件下载)(0816-林雪阵)

 

 服务器 

头文件 

#ifndef __HEAD_H__
#define __HEAD_H__

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

//打印错误信息宏函数
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0)

//用户信息结构体
typedef struct node{
	struct sockaddr_in cin;
	int newfd;
	int size;
	struct node *next;
}USER;


#define PORT 8888               //1024~49151
#define IP "192.168.31.72"    //本机IP  ifconfig查看
#define PATH "./"

//创建链表
USER* create_list(int sfd);
//服务器发送线程
void* wri_send(void*arg);
//发送信息
int send_msg(int newfd,char *buf,int size);
//删除指定节点
int delet_point(USER *H,int sfd);

//处理客户端信息线程
void *deal_climsg(void *arg);


#endif

 功能文件

#include "head.h"

//创建链表
USER * create_list(int sfd)
{
	//创建链表
	USER *H=(USER*)malloc(sizeof(USER));
	if(NULL==H)
	{
		puts("链表创建失败");
		return NULL;
	}
	//初始化链表
	H->next=NULL;
	H->size=0;
	H->newfd=sfd;
	return H;
}

//发送信息
int send_msg(int newfd,char *buf,int size)
{
	ssize_t res;
	if((res=send(newfd,buf,size,0))<0)
	{
		ERR_MSG("send");
		return -1;
	}
	return 0;
}



//服务器发送系统信息线程
void* wri_send(void*arg)
{
	pthread_detach(pthread_self());
	char buf[128]="";
	ssize_t res;
	USER *H=(USER*)arg;
	while(1)
	{
		bzero(buf,sizeof(buf));
		//printf("请输入要传输的:\n");
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1]=0;
		USER *p=H->next;
		while(p!=NULL)
		{
			int newfd=p->newfd;
			if(send_msg(newfd,buf,sizeof(buf))<0)
			{
				return NULL;
			}
			p=p->next;
		}
	}
}


//删除指定节点
int delet_point(USER *H,int sfd)
{
	USER *p=H;
	while(p->next!=NULL)
	{
		if(p->next->newfd == sfd)
		{
			USER *q=p->next;
			p->next=q->next;

			free(q);
			q=NULL;
			break;
		}
		p=p->next;
	}
	return 0;
}

//处理客户端信息线程
void *deal_climsg(void *arg)
{
	pthread_detach(pthread_self());
	USER *H=(USER*)arg;
	USER *p=H;
	while(p->next!=NULL)
	{
		p=p->next;
	}
	int newfd =p->newfd;
	char buf[128]="";
	ssize_t res=0;
	//循环接收
	while(1)
	{
		bzero(buf,sizeof(buf));
		res=recv(newfd,buf,sizeof(buf),0);
		if(res<0)
		{
			ERR_MSG("recv");
			return NULL;
		}
		else if(0==res)
		{
			printf("[%s : %d] newfd =%d客户端退出\n",inet_ntoa((p->cin).sin_addr),ntohs((p->cin).sin_port),newfd);
			delet_point(H,newfd);
			break;
		}
		if(strcmp(buf,"readdir")==0)
		{
			//打开指定目录
			DIR* dp=opendir(PATH);
			if(NULL== dp)
			{
				ERR_MSG("opendir");
				return NULL;
			}
			struct dirent* rp=NULL;
			//发送目录信息
			char arr[128]="目录:";
			send_msg(newfd,arr,sizeof(arr));
			while(1)
			{
				bzero(arr,sizeof(arr));
				rp=readdir(dp);
				if(NULL == rp)
				{
					if(0==errno)
					{
						break;
					}else
					{
						ERR_MSG("readdir");
						return NULL;
					}
				}
				if(rp->d_name[0]=='.')
					continue;
				strcpy(arr,rp->d_name);
				send_msg(newfd,arr,sizeof(arr));
			}
			//关闭目录
			closedir(dp);
		}else if(strcmp(buf,"download")==0)
		{
			//判断并发送提示下载信息
			char brr[128]="请选择要下载的文件:";
			send_msg(newfd,brr,sizeof(brr));
			bzero(brr,sizeof(brr));
			ssize_t res1;
			res1=recv(newfd,brr,sizeof(brr),0);
			if(res1<0)
			{
				ERR_MSG("recv");
				return NULL;
			}
			else if(0==res1)
			{
				printf("[%s : %d] newfd =%d客户端退出\n",inet_ntoa((p->cin).sin_addr),ntohs((p->cin).sin_port),newfd);
				delet_point(H,newfd);
				break;
			}
			//发送开始下载标示
			char stat[128]="";
			strcpy(stat,"开始发送");
			send_msg(newfd,stat,sizeof(stat));
			//打开要发送的文件
			char crr[128]="";
			strcpy(crr,PATH);
			strcat(crr,brr);
			printf("%s\n",crr);
			int fd_r=open(crr,O_RDONLY);
			if(fd_r<0)
			{
				ERR_MSG("open");
				return NULL;
			}
			//循环读取发送信息
			ssize_t res_rd;
			int i=1;
			while(1)
			{
				bzero(brr,sizeof(brr));
				res_rd=read(fd_r,brr,sizeof(brr));
				if(res_rd<0)
				{
					ERR_MSG("read");
					return NULL;
				}else if(0==res_rd)
				{
					printf("文件传输完成\n");	
					break;
				}
				send_msg(newfd,brr,res_rd);
			}

		}
		printf("[%s : %d] newfd =%d:%s\n",inet_ntoa((p->cin).sin_addr),ntohs((p->cin).sin_port),newfd,buf);
	}

}

主函数

#include "head.h"

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

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

	//填充地址信息结构体,真是的地址信息结构体与协议族相关
	//AF_INET,所以详情请看man 7ip
	struct sockaddr_in sin;
	sin.sin_family      = AF_INET;
	sin.sin_port        = htons(PORT);      //网络字节序端口号
	sin.sin_addr.s_addr = inet_addr(IP) ;  //网络字节序的IP地址

	//将地址信息结构体绑定到套接字上
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bing success\n");

	//将套接字设置为被动监听状态
	if(listen(sfd,128)<0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success\n");

	//创建链表
	USER *H=create_list(sfd);
	if(NULL==H) return -1;

	//网络字节序的IP-->点分十进制,网络字节序的port-->本机字节序
	//printf("[%s : %d] newfd =%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);

	pthread_t tid1;

	if(pthread_create(&tid1,NULL,wri_send,(void*)H)<0)
	{
		ERR_MSG("pthread_create");
		return -1;
	}

	while(1)
	{
		struct sockaddr_in cin;
		socklen_t addrlen = sizeof(cin);
		//从已完成连接的队列头中,取出一个客户端的信息,创建生成一个新的套接字文件描述符
		//该文件描述符才是与客户端通信的文件描述符
		int newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen);
		if(newfd < 0)
		{
			ERR_MSG("accept");
			return -1;
		}
		//判断是不是新的客户
		USER *p=H;
		while(p->next!=NULL)
		{
			if(newfd==p->newfd)
			{
				break;
			}
			p=p->next;
		}
		if(NULL==p->next)
		{
			//初始化新增节点
			USER *new=(USER*)malloc(sizeof(USER));
			new->newfd=newfd;
			new->cin=cin;
			new->next=NULL;
			
			//尾插连入链表
			p->next=new;
			//表的变化
			H->size++;

			//创建新的客户线程
			pthread_t tid2;
			if(pthread_create(&tid2,NULL,deal_climsg,(void*)H)<0)
			{
				ERR_MSG("pthread_create");
				return -1;
			}
		}
	}

	close(sfd);

	return 0;
}

 客户端

 

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

//打印错误信息宏函数
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0)

//服务器IP和端口号
#define PORT 8888               //1024~49151
#define IP "192.168.31.72"    //本机IP  ifconfig查看


void* wri_send(void*arg)
{
	pthread_detach(pthread_self());
	char buf[128]="";
	ssize_t res;                              
	int sfd=*((int*)arg);
	while(1)
	{
		printf("请输入要传输的:\n");
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1]=0;
		res=send(sfd,buf,sizeof(buf),0);
		if(res<0)
		{
			ERR_MSG("send");
			return NULL;
		}
		
	}
}

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

	//允许端口快速复用
	int reuse=1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	printf("setsockopt 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(connect(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("connect");
		return -1;
	}

	//创建发送线程
    pthread_t tid;
    if(pthread_create(&tid,NULL,wri_send,(void*)&sfd)<0)
    {
        ERR_MSG("pthread_create");
        return -1;
    }

	ssize_t res=0;
	char arr[5]="";
	char buf[128]="";
	
	//发送
	while(1)
	{
		
		//接收
		bzero(buf,sizeof(buf));
		res=recv(sfd,buf,sizeof(buf),0);
		if(res<0)
		{
			ERR_MSG("recv");
			return -1;
		}else if(res==0)
		{
			printf("服务器关闭\n");
			break;
		}
		printf("%s\n",buf);
		

		if(strcmp(buf,"开始发送")==0)
		{
			int fd_w=open("copy.c",O_WRONLY|O_CREAT|O_TRUNC,0664);
			if(fd_w<0)
			{
				ERR_MSG("open");
				return -1;
			}
			//循环接收信息并写进文件
			char brr[128]="";
			ssize_t res_w;
			while(1)
			{
				bzero(brr,sizeof(brr));
				res_w=recv(sfd,brr,sizeof(brr),0);
				if(res_w<0)
				{
					ERR_MSG("recv");
					return -1;
				}else if(res_w==0)
				{
					printf("服务器关闭\n");
					return -1;
				}

				if(res_w<sizeof(brr))
				{
					if(write(fd_w,brr,res_w)<0)
					{
						ERR_MSG("write");
						return -1;
					}
					printf("文件传输完成\n");
					break;
				}else{

					if(write(fd_w,brr,res_w)<0)
					{
						ERR_MSG("write");
						return -1;
					}
				}
			}
		}
	}

	close(sfd);

	return 0;
}

功能实现示例:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林某某..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值