这是上传文件的一个示例,可以参照自行修改成下载或者其它功能。
在上传时,需要先将文件名传到服务器端,这是采用一个结构体,包含文件名及文件名长度(可以用于校验),防止文件名乱码。
client
#include <stdio.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include "wrap.h" #define MAXLINE 1492 #define SERV_PORT 5555 #define FILE_NAME_LEN 64 struct fileInfo{ char fileName[FILE_NAME_LEN]; int len; }; int main(int argc, char *argv[]) { if(argc<3){ perror("Usage:./a.out ip filename"); exit(-1); } struct sockaddr_in servaddr; char buf[MAXLINE]; int sockfd; //char servip[]="123.206.59.137"; sockfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET, argv[1], &servaddr.sin_addr); servaddr.sin_port = htons(SERV_PORT); Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); struct fileInfo file_name; memset(&file_name,0,sizeof(file_name)); strncpy(file_name.fileName,argv[2],strlen(argv[2])); file_name.len=strlen(argv[2]); Write(sockfd,&file_name,sizeof(file_name)); FILE *fp=fopen(argv[2],"r"); if(fp==NULL){ perror("open file failed"); Close(sockfd); exit(-1); } printf("open file %s successed ",argv[2]); int len=0; while ((len=fread(buf,sizeof(char),MAXLINE,fp))>0) { Write(sockfd, buf, len); } fclose(fp); Close(sockfd); return 0; }
server
#include <stdio.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <pthread.h> #include "wrap.h" #define MAXLINE 1492 #define SERV_PORT 5555 #define FILE_NAME_LEN 64 struct fileInfo{ char fileName[FILE_NAME_LEN]; int len; }; int main(int argc, char *argv[]){ struct sockaddr_in serveraddr; int listenfd; char str[INET_ADDRSTRLEN]; listenfd=Socket(AF_INET,SOCK_STREAM,0); bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family=AF_INET; serveraddr.sin_addr.s_addr=htonl(INADDR_ANY); serveraddr.sin_port=htons(SERV_PORT); Bind(listenfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); Listen(listenfd,20); while(1){ struct sockaddr_in clientaddr; socklen_t addrLen=sizeof(clientaddr); int confd=Accept(listenfd,(struct sockaddr *)&clientaddr,&addrLen); printf("receive file from %s at port %d ", inet_ntop(AF_INET,&clientaddr.sin_addr,str,sizeof(str)), ntohs(clientaddr.sin_port) ); int len=0; struct fileInfo file_name; len=Read(confd,&file_name,sizeof(file_name)); if(len==0){ Close(confd); }else { printf("file name len=%d ",file_name.len); printf("file name is %s ",file_name.fileName); } char buf[MAXLINE]; FILE *fp=fopen(file_name.fileName,"w"); if(!fp){ perror("open file failed"); Close(confd); Close(listenfd); } while((len=Read(confd,buf,MAXLINE))>0){ fwrite(buf,sizeof(char),len,fp); } if(len==0){ fclose(fp); printf("receive file done "); Close(confd); } } Close(listenfd); return 0; }
wrap.c
#include "wrap.h" /********************************************************************* * * Name : perr_exit * * Description : exit the function * * Input : the error string * * Output : * * Return : * * Others : by jzk 2009.12.02 * **********************************************************************/ void perr_exit(const char *s) { perror(s); exit(1); } /********************************************************************* * * Name : Accept * * Description : accept a connection on a socket * * Input : fd---a socket that has been created * * sa---a pointer to a sockaddr structure * * salenptr---actual size of the peer address * * Output : * * Return : the descriptor for the accepted socket * * Others : by jzk 2009.12.02 * **********************************************************************/ int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr) { int n; again: if((n = accept(fd, sa, salenptr)) < 0) { if((ECONNABORTED == errno) || (EINTR == errno)) goto again; else perr_exit("accept error"); } return n; } /********************************************************************* * * Name : Bind * * Description : bind a name to a socket * * Input : fd---a socket that has been created * * sa---a pointer to a sockaddr structure * * salen---the size of the address structure * * Output : * * Return : * * Others : by jzk 2009.12.02 * **********************************************************************/ void Bind(int fd, const struct sockaddr *sa, socklen_t salen) { if(bind(fd, sa, salen) < 0) perr_exit("bind error"); } /********************************************************************* * * Name : Connect * * Description : initiate a connection on a socket * * Input : fd---a socket that has been created * * sa---a pointer to a sockaddr structure * * salen---the size of the address structure * * Output : * * Return : * * Others : by jzk 2009.12.02 * **********************************************************************/ void Connect(int fd, const struct sockaddr *sa, socklen_t salen) { if(connect(fd, sa, salen) < 0) perr_exit("connect error"); } /********************************************************************* * * Name : Listen * * Description : listen for connections on a socket * * Input : fd---a socket that has been created * * backlog---the maximum length to the queue of * * pending connections * * Output : * * Return : * * Others : by jzk 2009.12.02 * **********************************************************************/ void Listen(int fd, int backlog) { if(listen(fd, backlog) < 0) perr_exit("listen error"); } /********************************************************************* * * Name : Socket * * Description : create an endpoint for communication * * Input : family---a communication domain * * type---the communication semantics * * protocol---a particular protocol for the socket * * Output : * * Return : return a descriptor of the socket * * Others : by jzk 2009.12.02 * **********************************************************************/ int Socket(int family, int type, int protocol) { int n; if((n = socket(family, type, protocol)) < 0) perr_exit("socket error"); return n; } /********************************************************************* * * Name : Read * * Description : read from a file descriptor * * Input : fd---a socket that has been created * * ptr---the buffer which storage the bytes * * nbytes---the number of bytes read * * Output : * * Return : return the number of bytes read * * Others : by jzk 2009.12.02 * **********************************************************************/ ssize_t Read(int fd, void *ptr, size_t nbytes) { ssize_t n; again: if((n = read(fd, ptr, nbytes)) == -1) { if(EINTR == errno) goto again; else return -1; } return n; } /********************************************************************* * * Name : Write * * Description : write to a file descriptor * * Input : fd---a socket that has been created * * ptr---buffer of the bytes * * nbytes---the number of bytes written * * Output : * * Return : return the number of bytes written * * Others : by jzk 2009.12.02 * **********************************************************************/ ssize_t Write(int fd, const void *ptr, size_t nbytes) { ssize_t n; again: if((n = write(fd, ptr, nbytes)) == -1) { if(EINTR == errno) goto again; else return -1; } return n; } /********************************************************************* * * Name : Close * * Description : close a file descriptor * * Input : fd---a socket that has been created * * Output : * * Return : * * Others : by jzk 2009.12.02 * **********************************************************************/ void Close(int fd) { if(close(fd) == -1) perr_exit("close error"); } /********************************************************************* * * Name : Readn * * Description : read from a file descriptor, * * make sure read the enough bytes * * Input : fd---a socket that has been created * * ptr---the buffer which storage the bytes * * nbytes---the number of bytes read * * Output : * * Return : return the number of bytes read * * Others : by jzk 2009.12.02 * **********************************************************************/ ssize_t Readn(int fd, void *vptr, size_t nbytes) { size_t nleft; size_t nread; char *ptr; ptr = vptr; nleft = nbytes; while(nleft > 0) { if((nread = read(fd, ptr, nleft)) < 0) { if(EINTR == errno) nread = 0; else return -1; } else if(nread == 0) break; nleft -= nread; ptr += nread; } return (nbytes-nleft); } /********************************************************************* * * Name : Writen * * Description : write to a file descriptor, * * make sure write the enough bytes * * Input : fd---a socket that has been created * * ptr---the buffer which storage the bytes * * nbytes---the number of bytes read * * Output : * * Return : return the number of bytes read * * Others : by jzk 2009.12.02 * **********************************************************************/ ssize_t Writen(int fd, const void *vptr, size_t nbytes) { size_t nleft; size_t nwritten; const char *ptr; ptr = vptr; nleft = nbytes; while(nleft > 0) { if((nwritten = write(fd, ptr, nleft)) <= 0) { if(nwritten < 0 && EINTR == errno) nwritten = 0; else return -1; } nleft -= nwritten; ptr += nwritten; } return nbytes; } static ssize_t my_read(int fd,char *ptr) { static int read_cnt; static char *read_ptr; static char read_buf[100]; if(read_cnt<=0){ again: if((read_cnt=read(fd,read_buf,sizeof(read_buf))<0)){ if(errno==EINTR) goto again; return -1; }else if(read_cnt==0) return 0; read_ptr=read_buf; } read_cnt--; *ptr=*read_ptr++; return 1; } size_t Read_line(int fd,void *vptr,size_t maxlen) { ssize_t n,rc; char c,*ptr; ptr=vptr; for(n=1;n<maxlen;n++){ if((rc=my_read(fd,&c))==1){ *ptr++=c; if(c==' ') break; }else if(rc==0){ *ptr=0; return n-1; }else return -1; } *ptr=0; return n; }
wrap.h
#ifndef WRAP_H #define WRAP_H #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <sys/socket.h> void perr_exit(const char *s); int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr); void Bind(int fd, const struct sockaddr *sa, socklen_t salen); void Connect(int fd, const struct sockaddr *sa, socklen_t salen); void Listen(int fd, int backlog); int Socket(int family, int type, int protocol); void Close(int fd); ssize_t Read(int fd, void *ptr, size_t nbytes); ssize_t Write(int fd, const void *ptr, size_t nbytes); ssize_t Readn(int fd, void *vptr, size_t n); ssize_t Writen(int fd, const void *vptr, size_t n); ssize_t Readline(int fd, void *vptr, size_t maxlen); #endif
Makefile
###################################### # ####################################### #source file #源文件,自动找所有.c和.cpp文件,并将目标定义为同名.o文件 SOURCE := $(wildcard *.c) $(wildcard *.cpp) OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE))) #target you can change test to what you want #目标文件名,输入任意你想要的执行文件名 TARGET := client server APP1 := client APP2 := server MAINS :=$(APP1).o $(APP2).o #compile and lib parameter #编译参数 CC := gcc LIBS := -lpthread -lrt LDFLAGS := DEFINES := INCLUDE := -I. CFLAGS := -g -Wall -O3 $(DEFINES) $(INCLUDE) CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H #i think you should do anything here #下面的基本上不需要做任何改动了 .PHONY : everything objs clean veryclean rebuild everything : $(TARGET) all : $(TARGET) objs : $(OBJS) rebuild: veryclean everything clean : rm -fr *.so rm -fr *.o veryclean : clean rm -fr $(TARGET) $(APP1) :$(APP1).o $(filter-out $(MAINS), $(OBJS)) $(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) $(APP2) :$(APP2).o $(filter-out $(MAINS), $(OBJS)) $(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)