局域网文件传输小程序
上一篇 / 下一篇 2010-05-13 21:22:25 / 个人分类:linux
在学了计算机网络之后,为了更好地理解、掌握和应用一些网络知识,需要用做一个课程设计等方式来巩固网络知识和应用这些知识。TCP协议是在实际应用中应用广泛的协议,因而掌握TCP协议具有十分重要的意义。
2总体设计
2.1系统或算法框架设计
本系统有两部分:一个服务器端,负责接收文件;一个客户端,负责发送文件。
系统采用套接字(socket)通信,套接字(socket)是一种通信机制,客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行。
2.2功能设计
2.3平台设计
硬件:不限
操作系统:GNU/Linux系统
2.4数据结构的设计
struct
sockaddr_in{
short
sin_family;/*socket()系统调用的协议族如AF_INET*/
u_short
sin_port;/*网络字节次序形式的端口号码*/
struct
in_addr sin_addr;/*网络字节次序形式的网络地址*/
char
sin_zero[8];
}
2.5接口设计
ssize_t readline(int fd, void * vptr, size_t maxlen)
;
接收一个包含文件名的TCP包
int
socket(int family,int type,int protocol)
其中:
(1)family指明套节字族,其值包括:
AF_UNIX (UNIX内部协议族)
AF_INET (Iternet协议)
AF_NS
(XeroxNs协议,TCP/IP编程取该值)
AF_IMPLINK (IMP链接层)
在本系统中,用AF_INET
(2)type指明套接字类型,取值有:
SOCK_STREAM (流套接字)
SOCK_DGRAM (数据报套接字)
SOCK_RAW
(原始套接字)
SOCK_SEQPACKET (定序分组套接字)
在本系统中,用SOCK_STREAM
详见Linux的帮助手册:man
socket
3详细设计
3.1原理
运行服务器server,服务器监听9734端口,等待客户端的请求;客户端发出连接请求,服务器接受请求,建立连接。客户端发送一个TCP包,里面包含需要传输的文件名,服务器端接收到含有文件名的TCP包后在本地磁盘创建文件。然后客户端开始发送文件,每次发送2048个字节(最后一次可能小于2048字节),直到文件传输完成。
3.2服务器端关键代码
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(PORT);
bind(server_sockfd, (struct sockaddr *) &server_address,
sizeof(server_address));
listen(server_sockfd, 5);
说明:打开socket,进行监听所有连接请求
while(len = read(client_sockfd, buffer, LENGTH))
{
if(len < 0)
{
printf("socket read error\n");
exit(1);
}
if(fwrite(buffer, 1, len, fp) < 0)
{
printf("Error while writing to file %s",filename);
exit(1);
}
}
说明:一边从客户端接收文件,一边把文件保存到本地磁盘。
if(readline(client_sockfd, buffer, LENGTH) < 0)
{
printf("Error! Can not receive packege.\n");
exit(1);
}
说明:接收一个包含文件名的TCP包
3.3客户端关键代码
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(argv[2]);
address.sin_port = htons(9734);
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *)&address, len);
说明:打开socket,向服务器端发出连接请求
while(len = fread(buffer, 1, LENGTH, fp))
{
if(len < 0)
{
printf("read file error\n");
exit(1);
}
if(write(sockfd, buffer, len) < 0)
{
printf("Error while write to the socket.\n");
exit(1);
}
}
说明:一边从本地读文件,一边向服务器端发送文件
write(sockfd, filename, strlen(filename));
printf("will transferfile:%s\n",filename);
说明:向服务器端发送文件名。
3.3客户端详细设计
#define LENGTH 2048
int main(int argc, char *argv[])
{
int sockfd;
int len;
struct sockaddr_in address;
int result;
char *buffer[LENGTH+1];
char filename[LENGTH+1];
FILE *fp;
int i;
if(argc != 3)
{
printf("Error! Parameter is not right,please see ./client2 -h\n");
exit(1);
}
else if((*argv[1] == '-') && (*(argv[1]+1) == 'h'))
{
printf("Usage: ./client <filename> <serverIP>\n");
exit(1);
}
else
{
memcpy(filename, argv[1], strlen(argv[1]));
filename[strlen(argv[1])] = '\n';
filename[strlen(argv[1]) + 1] = 0;
}
//打开文件
if((fp = fopen(argv[1],"rb+")) == NULL)
{
printf("Error! Can not open file %s", filename);
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(argv[2]);
address.sin_port = htons(9734);
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1)
{
perror("oops:client1");
exit(1);
}
write(sockfd, filename, strlen(filename));
printf("will transfer file:%s\n",filename);
while(len = fread(buffer, 1, LENGTH, fp))
{
if(len < 0)
{
printf("read file error\n");
exit(1);
}
if(write(sockfd, buffer, len) < 0)
{
printf("Error while write to the socket.\n");
exit(1);
}
}
fclose(fp);
close(sockfd);
printf("file %s transferred !\n",argv[1]);
return 0;
}
3.2服务器端详细设计
#define PORT 9734
#define LENGTH 2048
int main(int argc, char *argv[])
{
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
int i,len;
FILE *fp;
char filename[LENGTH+1];
ssize_t readlilne(int fd, void *vptr, size_t maxlen);
//缓存
char buffer[LENGTH+1];
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(PORT);
bind(server_sockfd, (struct sockaddr *) &server_address,
sizeof(server_address));
listen(server_sockfd, 5);
while(1)
{
printf("server waiting...\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr *) &client_address, &client_len);
printf("reading filename......\n");
//接收一个包含文件名的TCP包
if(readline(client_sockfd, buffer, LENGTH) < 0)
{
printf("Error! Can not receive packege.\n");
exit(1);
}
buffer[strlen(buffer) - 1] = 0;
memcpy(filename, buffer, LENGTH + 1);
printf("will save to file:%s\n",buffer);
//打开文件
if((fp = fopen(filename, "wb+") ) == NULL)
{
printf("Error! Can not open file:%s", filename);
exit(1);
}
//接收文件
while(len = read(client_sockfd, buffer, LENGTH))
{
if(len < 0)
{
printf("socket read error\n");
exit(1);
}
if(fwrite(buffer, 1, len, fp) < 0)
{
printf("Error while writing to file %s",filename);
exit(1);
}
}
fclose(fp);
close(client_sockfd);
printf("file %s received!\n");
}
close(server_sockfd);
return 0;
}
ssize_t readline(int fd, void * vptr, size_t maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++) {
again:
if ((rc = read(fd, &c, 1)) == 1) {
*ptr++ = c;
if (c == '\n') {
break;
}
} else if (rc == 0) { /* EOF */
*ptr = 0;
return (n - 1);
} else {
if (errno == EINTR) {
goto again;
}
return (-1);
}
}
*ptr = 0;
return (n);
}
《Linux程序设计(第3版)》Neil Matthew , Richard Stones著,陈健、宋健健译,人民邮电出版社。
《计算机网络》 吴功宜编著 清华大学出版社
《C程序设计(第三版)》 谭浩强著 清华大学出版社
相关阅读:
- oracle sqlloader控制文件的例子 (blackspace, 2008-11-24)
- 引导加载程序之争:了解 LILO 和 GRUB (CGArt, 2009-10-24)
- 最小化您的程序到系统托盘 (uunuu, 2009-12-02)
- [转]使用 GDB 调试多进程程序 (pate, 2010-3-08)
