参考书本做了一个简易的文件传输系统,对网络编程,文件操作进行复习。
系统调用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)
测试