TCP 文件服务器 (将服务器上的文件全部发给客户端)示例代码

/* 并发服务器模型 */

/* TCP文件服务器代码 */


/*  头文件  */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <errno.h>
#include <sys/fcntl.h>
#include <sys/wait.h>

/* 宏定义 */
#define DEFAULT_SVR_PORT 2828
#define FILE_MAX_LEN 64


/* 全局变量区 */
char  filename[FILE_MAX_LEN+1];


/*  handle_cilent函数  */

static void *handle_cilent(void *arg)
{
	int sock = (int)arg;
	char buf[1024];
	int len,ret;
	FILE *fp;

	printf("Begin Send!\n");
	
	fp = fopen(filename,"r");
	if(NULL == fp)
	{
		close(sock);
		exit(6);
	}


	/* 发文件名 */
	
	ret = send(sock,filename,FILE_MAX_LEN,0);
	if(-1 == ret)
	{
		perror("Send file name");
		goto EXIT_THREAD;
	}

	printf("Begin send file %s ...\n",filename);


	/* 发送文件内容 */

	while(!feof(fp))
	{
		len = fread(buf,1,sizeof(buf),fp);

		printf("Sever read %s ,len %d \n",filename,len);

		ret = send(sock,buf,len,0);
		if(ret < 0)
		{
			perror("Send file content");
			goto EXIT_THREAD;
		}
	}


	EXIT_THREAD:
	if(fp)
	close(fp);

	close(sock);
}








/* main函数 */
int main(int argc , char *argv[])
{
	int sockfd,newfd;
	int ret;
	int sin_size,numbytes;
	
	/* 定义2个IPV4地址 */

	struct sockaddr_in my_addr;
	struct sockaddr_in their_addr;
	pthread_t thread;
	unsigned short port;
	
	if(argc < 2)
	{
		printf("Please input a filename without path\n");
		exit(1);
	}

	strncpy(filename,argv[1],FILE_MAX_LEN);
	port = DEFAULT_SVR_PORT;
	if(argc >= 3)
	{
		port = (unsigned short)atoi(argv[2]);
	}




	/* 第一步:建立TCP套接字socket */
	/* AF_INET :ip通信  SOCK_STREAM:TCP */

	sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == sockfd)
	{
		perror("socket");
		exit(2);
	}

	
	/* 第二步:设置监听端口 
		功能:初始化结构体,并绑定2828端口 */

	memset(&my_addr,0,sizeof(struct sockaddr));
	
	my_addr.sin_family = AF_INET;  // IPV4 
	my_addr.sin_port = htons(port); //设置监听端口为2828,用htons转成网络序 
	my_addr.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY来表示任意IP地址可能通信


	/* 第三步:绑定套接字,把socket队列于端口关联起来 */

	ret = bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));
	if(-1 == ret)
	{
		perror("bind error");
		goto EXIT_MAIN;
	}


	/* 第四步:开始在2828端口监听,是否有客户端发来连接 */

	ret = listen(sockfd,10);
	if(-1 == ret)
	{
		perror("listen");
		goto EXIT_MAIN;
	}

	printf("Listen Port:%d !\n",port);
	

	/* 循环与客户端通信 */

	while(1)
	{
		sin_size = sizeof(struct sockaddr_in);
		printf("\nSever waiting ... \n");

		//如果有客户端建立连接,将会产生一个全新的套接字newfd,专门用于和这个客户端通信 

		newfd = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size);
		if(-1 == newfd)
		{
			perror("accept");
			goto EXIT_MAIN;
		}
		
		printf("Cilent  (ip = %d : port = %d ) request !\n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port));

		
		//生成一个线程来完成与客户端的对话,父进程继续监听
		pthread_create(&thread,NULL,handle_cilent,(void *)newfd);
	}


	/* 第六步:关闭Socket */

	EXIT_MAIN:
	close(sockfd);

	return 0;
}


/* TCP 文件接收客户端 */

#include "Head.h"  //自己写的头文件

#define FILE_MAX_LEN 64
#define DEFAULT_SVR_PORT 2828

int main(int argc,char *argv[])
{
	int sockfd,ret,total,len;
	char ip_addr[64];
	unsigned short port;
	struct hostent *he;
	struct sockaddr_in	their_addr;
	char filename[FILE_MAX_LEN+1],buf[1024];
	FILE *fp ;

	if(argc < 2)
	{
		printf("Need s sever ip!\n");
		exit(1);
	}
	
	strncpy(ip_addr,argv[1],sizeof(ip_addr));
	port = DEFAULT_SVR_PORT;
	if(argc >= 3)
	{
		port = (unsigned short)atoi(argv[2]);
	}

	/* 域名解析 */
	// he = gethostbyname(argv[1]);
	

	/* 第一步: 建立一个TCP套接字 */

	sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == sockfd)
	{
		perror("sockfd");
		exit(2);
	}


	/* 第二步:设置服务器地址和端口2828 */

	memset(&their_addr,0,sizeof(their_addr));

	their_addr.sin_family = AF_INET;
	their_addr.sin_port = htons(port);
	their_addr.sin_addr.s_addr = inet_addr(ip_addr);

	printf("Conect Sever %s :%d  \n",ip_addr,port);


	/* 第三步: 用connect 和服务器建立连接,使用协议栈自动分配端口 */
	
	ret = connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr));
	if(-1 == ret)
	{
		perror("connect");
		exit(3);
	}

	ret = send(sockfd,"Hello",6,0);
	if(ret < 0)
	{
		perror("send");
		exit(4);
	}

	/* 接收文件名 */
	
	total = 0;
	while(total < FILE_MAX_LEN)
	{
		//接收的buf长度,始终是未接收的文件名长度剩下的长度 

		len = recv(sockfd,filename+total,(FILE_MAX_LEN - total),0);
		if(len <= 0)
		{
			break;
		}

		total += len;
	}

	/* 接收文件名出错 */
	if(total != FILE_MAX_LEN)
	{
		perror("failure file name");
		exit(5);
	}

	printf("recv file %s ...\n",filename);
	
	fp = fopen(filename,"wb");
	if(NULL == fp)
	{
		perror("open");
		exit(6);
	}

	
	/* 接收文件数据 */

	printf("\nRec File Begin!\n");

	total = 0;
	while(1)
	{
		len = recv(sockfd,buf,sizeof(buf),0);
		if(-1 == len)
		{
			break;
		}

		total += len;

		//写入本地文件
		fwrite(buf,1,len,fp);
	}

	
	fclose(fp);
	
	printf("Recv file %s success! Total length:%d  \n",filename,total);


	/* 关闭socket */

	close(sockfd);
	return 0;
}

后记:学而思,思而问,问而后多敲代码


  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值