參考書本做了一個簡易的文件傳輸系統,對網絡編程,文件操作進行復習。
系統調用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 <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)
測試