簡易的文件傳輸系統

參考書本做了一個簡易的文件傳輸系統,對網絡編程,文件操作進行復習。

系統調用socket

頭文件 #include <sys/socket.h>
#include <sys/types.h>
原型 int socket(int domain,int type,int protocol)
參數

domain:網絡程序所在的主機採用的通用協議簇(AF_UNIX、AF_INET等)AF_UNIX只能夠用於單一的UNIX系統進程間通信,而AF_INET是針對internet的,允許在遠程主機之間通信

type:網絡程序所採用的通信協議,可以理解成套接字的類型。其中SOCK_STREAM代表流式套接字,即表明採用TCP的協議;SOCK_DGRAM爲數據報套接字,即表明採用UDP的協議

SOCK_RAW代表原始套接字

protocol:如果type指定爲SOCK_STREAM或SOCK_DGRAM,則已經確定協議,所以protocol置0;如果指定SOCK_RAW,還需要進一步指定協議,通過protocol指定,如IPPROTO_ICMP

返回值

成功:返回一個新的套接字描述符

失敗:返回-1,並置錯誤碼

系統調用bind

頭文件

#include <sys/socket.h>
#include <sys/types.h>

#include <arpa/inet.h>

原型 int bind(int sockfd,struct sockaddr *my_addr,socklen_t addrlen)
功能 綁定本機地址到套接字上
參數

sockfd:由socket調用返回的套接字描述符

my_addr:一個指向sockaddr的指針,實際應用中,一般使用指向struct sockaddr_in的指針代替

addrlen:sockaddr結構的長度

返回值

成功:返回0

失敗:返回-1,並置錯誤碼

備註

1:設置端口號時,可以選擇大於1024的端口號;如果端口號爲0,則表明由系統自動分配的端口號

2:設置ip地址時,如果地址爲INADDR_ANY,則表明自動加載本地ip

系統調用listen

頭文件 #include <sys/socket.h>
原型 int listen(int sockfd,int backlog)
功能

在bind對應的地址和端口上監聽

參數

sockfd: 由socket調用返回的套接字描述符

backlog:請求隊列的大小,一般爲20

返回值

成功:返回爲0

失敗:返回-1,並置錯誤碼

備註 backlog並不代表服務器端可同時處理的客戶端個數,而是向服務器端同時發起連接請求的客戶端的個數

系統調用accept

頭文件 #include <sys/socket.h>
#include <sys/types.h>
原型 int accept(int sockfd,struct sockaddr *addr socklen_t *addrlen)
功能

接收客戶端的連接請求

參數

sockfd: 由socket調用返回的套接字描述符

addr與addrlen:用來給客戶端的程序填寫的,服務器端只用傳遞對應類型的指針

返回值

成功:返回爲0

失敗:返回-1,並置錯誤碼

系統調用connect

頭文件 #include <sys/socket.h>
#include <sys/types.h>
原型 int accept(int sockfd,struct sockaddr *addr, socklen_t *addrlen)
功能

接收客戶端的連接請求

參數

sockfd: 由socket調用返回的套接字描述符

addr與addrlen:用來給客戶端的程序填寫的,服務器端只用傳遞對應類型的指針

返回值

成功:返回爲0

失敗:返回-1,並置錯誤碼

系統調用send

頭文件 #include <sys/socket.h>
#include <sys/types.h>
原型 ssize_t send(int s,const void* buf,size_t len,int flags)
功能

面向連接的套接字發送數據

參數

s:由socket調用返回的套接字描述符

buf:即將發送的數據區域的首地址

len:發送的數據區域字節個數

flags:標誌位

0:表明此時send功能與write相同

MSG_DONTROUTE:目標爲本地主機,告訴ip協議不查找路由表

返回值

成功:返回已經成功發送的字節個數

失敗:返回-1,並置錯誤碼

系統調用sendto

頭文件 #include <sys/socket.h>
#include <sys/types.h>
原型 ssize_t sendto(int s,const void* buf,size_t len,int flags,const struct sockaddr *to,socklen_t tolen);
功能

面向連接或面向無連接的套接字發送數據

參數

s:由socket調用返回的套接字描述符

buf:即將發送的數據區域的首地址

len:發送的數據區域字節個數

flags:標誌位

0:表明此時send功能與write相同

MSG_DONTROUTE:目標爲本地主機,告訴ip協議不查找路由表

to:對方地址信息

tolen:對方字節

返回值

成功:返回已經成功發送的字節個數

失敗:返回-1,並置錯誤碼

系統調用recv

頭文件 #include <sys/socket.h>
#include <sys/types.h>
原型 ssize_t recv(int s, void* buf,size_t len,int flags);
功能

面向連接的套接字接收數據

參數

s:由socket調用返回的套接字描述符

buf:即接收的數據區域的首地址

len:接收的數據區域字節個數

flags:標誌位

0:表明此時recv功能與read相同

MSG_PEEK:只查看數據,不讀出數據,下一次還能讀到剛纔的數據

MSG_WAITALL:等希望接收的數據字節個數到達個數到達後返回,否則阻塞等待,接收等待的條件:讀到指定的字節數據,讀到文件結束符,被信號中斷,發生錯誤

返回值

成功:返回已經成功發送的字節個數

失敗:返回-1,並置錯誤碼

系通調用recvfrom

頭文件 #include <sys/socket.h>
#include <sys/types.h>
原型 ssize_t recvfrom(int s, void* buf,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen);
功能

面向連接或面向無連接的套接字接收數據

參數

s:由socket調用返回的套接字描述符

buf:即接收的數據區域的首地址

len:接收的數據區域字節個數

flags:標誌位

0:表明此時recv功能與read相同

MSG_PEEK:只查看數據,不讀出數據,下一次還能讀到剛纔的數據

MSG_WAITALL:等希望接收的數據字節個數到達個數到達後返回,否則阻塞等待,接收等待的條件:讀到指定的字節數據,讀到文件結束符,被信號中斷,發生錯誤

from:對方地址信息

fromlen:保存對方地址長度

返回值

成功:返回已經成功發送的字節個數

失敗:返回-1,並置錯誤碼

服務器端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <error.h>
#include <fcntl.h>


#define MAXDATASIZE                 128
#define SERVPORT                    5623
#define BACKLOG                     5


void process_cli(int connfd,struct sockaddr_in client);
void proc_ls(int);
void proc_get(int,char*);
void proc_put(int,char*);

int main()
{
	int listenfd,connfd;
	struct sockaddr_in ser_addr,cli_addr;
    int len;
	pid_t pid;
	
	if((listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		printf("socket error!!!\n");
	}
	
	
	bzero(&ser_addr,sizeof(ser_addr));
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_port = htons(SERVPORT);
	ser_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	//bzero(&(ser_addr.sin_zero),8);
	
	if((bind(listenfd,(struct sockaddr *)&ser_addr,sizeof(struct sockaddr_in)))<0)
	{
		printf("bind");
		exit(1);
	}
	if(listen(listenfd,BACKLOG) < 0)
	{
		printf("listen");
		exit(1);
	}
	bzero(&cli_addr,sizeof(cli_addr));
	
	len = sizeof(struct sockaddr_in);
	while(1)
	{
		printf("-----------------------------\n");
		
		if((connfd = accept(listenfd,(struct sockaddr *)&cli_addr,&len)) < 0)
		{
			printf("accept");
			exit(1);
		}
		
		if((pid = fork()) > 0)
		{
			close(connfd);
			continue;
		}
		else if(pid == 0)
		{
			close(listenfd);
			process_cli(connfd,cli_addr);
			exit(0);
		}
		else
		{
			printf("fork");
			exit(0);
		}
		
		
	}
	
    close(listenfd);
	
    return 0;
}

int parse(char *buf,char **args)
{
	int num = 0;
	
	while(*buf != '\0')
	{
      while((*buf == ' ')||(*buf == '\t'||(*buf == '\n')))
		  *buf++ = '\0';
	    *args++=buf;
		++num;
	  while((*buf!='\0')&&(* buf!=' ')&&(*buf!='\t')&&(*buf!='\n'))
		  buf++;
	  
	}
	
	*args = '\0';
	return num;
		
		
}

void process_cli(int connfd,struct sockaddr_in client)
{
	char cmd[MAXDATASIZE];
	char *cmds[64];
	
	int cmdnum,num;
	
	bzero(cmd,MAXDATASIZE);
	
	num = recv(connfd,cmd,MAXDATASIZE,0);
	
	if(num == -1)
	{
		close(connfd);
		printf("recv");
		exit(1);
	}
	cmd[num - 1]= '\0';
	
	printf("%s command is %s.\n",inet_ntoa(client.sin_addr),cmd);
	
	cmdnum = parse(cmd,cmds);
	
	if(strcmp(cmds[0],"exit") == 0)
	{
		close(connfd);
		exit(0);
	}
	else if(strcmp(cmds[0],"ls") == 0)
	{
		proc_ls(connfd);
	}
	else if(strcmp(cmds[0],"get") == 0)
	{
		if(cmds[1] != 0)
		{
			proc_get(connfd,cmds[1]);
		}
		else
		{
			printf("error: get command missing filename\n");
			close(connfd);
		}
		
	}
	else if(strcmp(cmds[0],"put") == 0)
	{
		if(cmds[1] != 0)
		{
			proc_put(connfd,cmds[1]);
		}
		else
		{
			printf("error: put command missing filename\n");
			close(connfd);
		}
	}
	
}



void proc_ls(int sockfd)
{
	DIR *mydir = NULL;
	struct dirent* myitem = NULL;
	char cmd[MAXDATASIZE];
	bzero(cmd,MAXDATASIZE);
	
	if((mydir=opendir(".")) == NULL)
	{
		printf("opendir");
		exit(1);
	}
	
	while((myitem = readdir(mydir)) != NULL)
	{
		if(sprintf(cmd,myitem->d_name,MAXDATASIZE) < 0)
		{
			printf("sprintf error");
			exit(1);
		}
		
		if(write(sockfd,cmd,MAXDATASIZE) < 0)
		{
			printf("write");
			exit(1);
		}
		
	}
	
	closedir(mydir);
	close(sockfd);
	return;
}
	
void proc_get(int sockfd,char* filename)
{
	int fd,nbytes;
	char buffer[MAXDATASIZE];
	bzero(buffer,MAXDATASIZE);
	
	
	printf("get filename: [%s]\n",filename);
	
	if((fd = open(filename,O_RDONLY)) < 0)
	{
		printf("open");
		buffer[0] = 'N';
		if(write(sockfd,buffer,MAXDATASIZE)<0)
		{
			printf("prco_get write1");
			exit(1);
		}
		return;
	}
	
	
	buffer[0] = 'Y';
	if(write(sockfd,buffer,MAXDATASIZE)<0)
	{
		printf("proc_get write2");
        close(fd);
        exit(1);
	}
	
	while((nbytes = read(fd,buffer,MAXDATASIZE)) > 0)
	{
		if(write(sockfd,buffer,nbytes) < 0)
		{
			printf("proc_get write3");
			close(fd);
			exit(1);
		}
	}
	
	close(fd);
	close(sockfd);
	
    return ;
}
	
void proc_put(int sockfd,char *filename)
{
	int fd,nbytes;
	char buffer[MAXDATASIZE];
	bzero(buffer,MAXDATASIZE);
	
	printf("get filename:[%s]\n",filename);
	
	if((fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0)
	{
		printf("open");
		return;
	}
	
	while((nbytes=read(sockfd,buffer,MAXDATASIZE)) > 0)
	{
		if(write(fd,buffer,nbytes) < 0)
		{
			printf("proc_put write");
			close(fd);
			exit(1);
		}
	}
	
	close(fd);
	close(sockfd);
}

客戶端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <error.h>
#include <fcntl.h>


#define N                256
#define PORT             5623


typedef struct sockaddr SA;


void proc_menu();
void proc_exit();
void proc_ls(struct sockaddr_in,char *);
void proc_get(struct sockaddr_in,char *);
void proc_put(struct sockaddr_in,char *);


int main(int argc,char *argv[])
{
	char cmd[N];
	struct sockaddr_in addr;
	int len;
	proc_menu();
	bzero(&addr,sizeof(addr));
	
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr=inet_addr("127.0.0.1");
	len = sizeof(addr);
	
	while(1)
	{
		printf(">");
		bzero(cmd,N);
		if(fgets(cmd,N,stdin) == NULL)
		{
			printf("Fgets Error!\n");
			return -1;
		}
		
		
		cmd[strlen(cmd) - 1] = '\0';
		
		if(strncmp(cmd,"help",4) == 0)
		{
			proc_menu();
		}
		else if(strncmp(cmd,"exit",4) == 0)
	    {
			proc_exit(addr);
			exit(0);
		}
		else if(strncmp(cmd,"ls",2) == 0)
		{
			proc_ls(addr,cmd);
		}
		else if(strncmp(cmd,"get",3) == 0)
		{
			proc_get(addr,cmd);
		}
		else if(strncmp(cmd,"put",3) == 0)
		{
			proc_put(addr,cmd);
		}
		else
		{
			printf("command is error!please try again!\n");
		}
	}
	
	return 0;
}

int parse(char *buf,char **args)
{
	int num = 0;
	
	while(*buf != '\0')
	{
      while((*buf == ' ')||(*buf == '\t'||(*buf == '\n')))
		  *buf++ = '\0';
	    *args++=buf;
		++num;
	  while((*buf!='\0')&&(* buf!=' ')&&(*buf!='\t')&&(*buf!='\n'))
		  buf++;
	  
	}
	
	*args = '\0';
	return num;
		
}

void proc_menu()
{
	
	printf("\n-----------------------------------------------\n");
	printf("|  help:show all commands                       |\n");
	printf("|  exit:exit                                    |\n");
	printf("|  ls:show the file name list on server         |\n");
	printf("|  get filename:download file on server         |\n");
	printf("|  put filename:upload file on server           |\n");
	printf("-------------------------------------------------\n");
	
	
	return ;
}


void proc_exit(struct sockaddr_in addr)
{
	int sockfd;
	printf("Byte!\n");
	
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		printf("socket error!\n");
		exit(1);
	}
	
	if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
	{
		printf("connect error!\n");
		exit(1);
	}
	if(write(sockfd,"exit",N) < 0)
	{
		printf("write error!\n");
		exit(1);
	}
	
	close(sockfd);
	return;
}

void proc_ls(struct sockaddr_in addr,char *cmd)
{
	int sockfd;
	
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		printf("socket error!\n");
		exit(1);
	}
	if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
	{
		printf("connet error!\n");
		exit(1);
	}
	if(write(sockfd,cmd,N) < 0)
	{
		printf("write error!\n");
		exit(1);
	}
	
	while(read(sockfd,cmd,N) > 0)
	{
		printf("%s",cmd);
	}
	
	printf("\n");
	close(sockfd);
	
	return ;
	
}



void proc_get(struct sockaddr_in addr,char *cmd)
{
	int fd;
	int sockfd;
	char buffer[N];
	int nbytes;
	char *cmds[64];
	int cmdnum;
	
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		printf("socket error!\n");
		exit(1);
	}
	if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
	{
		printf("connet error!\n");
		exit(1);
	}
	if(write(sockfd,cmd,N) < 0)
	{
		printf("write error!\n");
		exit(1);
	}
	
	if(read(sockfd,buffer,N) < 0)
	{
		printf("read error!\n");
		exit(1);
	}
	
	if(buffer[0] == 'N')
	{
		close(sockfd);
		printf("can't open file");
		return;
	}
	cmdnum = parse(cmd,cmds);
	
	if((fd = open(cmds[1],O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0)
	{
		printf("open error!\n");
		exit(1);
	}
	while((nbytes = read(fd,buffer,N)) > 0)
	{
		if(write(sockfd,buffer,nbytes) < 0)
		{
			perror("proc_get get2");
		}
	}
	
	close(fd);
	close(sockfd);
	
    return ;
	
	
}

void proc_put(struct sockaddr_in addr,char *cmd)
{
	int fd;
	int sockfd;
	char buffer[N];
	int nbytes;
	char *cmds[64];
	int cmdnum;
	
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		printf("socket error!\n");
		exit(1);
	}
	if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
	{
		printf("connet error!\n");
		exit(1);
	}
	if(write(sockfd,cmd,N) < 0)
	{
		printf("write error!\n");
		exit(1);
	}
	
   cmdnum = parse(cmd,cmds);
	
	
	if((fd = open(cmds[1],O_RDONLY,0644)) < 0)
	{
		
		printf("open error!\n");
		exit(1);
	}
	while((nbytes = read(fd,buffer,N)) > 0)
	{
		if(write(sockfd,buffer,nbytes) < 0)
		{
			perror("proc_get put2");
		}
	}
	
	close(fd);
	close(sockfd);
	
    return ;
	
	
}

Makefile

DIR_SERVER=./serverfolder
DIR_CLIENT=./clientfolder
SP=$(DIR_SERVER)/server
C=$(DIR_CLIENT)/client
all:$(SP) $(C)
$(SP):$(SP).c
	gcc $^ -o $@
$(C):$(C).c
	gcc $^ -o $@
clean:
	rm -f $(SP)  $(C)

測試

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章