需求

当客户端连接上服务器后,服务器会将相应文件传输给客户端,实现文件下载。

思路

服务器端,主进程负责listen。循环内,主进程每从任务请求队列中accept出一个请求,就fork出孙子完成文件传输。注意:如果只是fork出儿子,那么主进程就得wait儿子,这样的话,只有当给一个客户端传完文件后才能下一个。

代码

server端

/*************************************************************************
> File Name: server.c
> Author: KrisChou
> Mail:zhoujx0219@163.com
> Created Time: Thu 28 Aug 2014 09:40:32 PM CST
************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#define SNDSIZE 1024*1024 //1M,注意如果栈空间(可以设置的)没这么大,就用堆空间
#define FILE_NAME "a.rmvb" int main(int argc,char* argv[])// exe config
{
/* 从配置文件中读取服务器联系方式:IP以及端口号 */
int fd_conf ;
fd_conf = open(argv[1], O_RDONLY) ;
FILE* fp_conf = fdopen(fd_conf, "r"); //秀一下fdopen函数,文件描述符转换为文件指针 fdopen(int fd, const char *mode)
char my_ip[32]="";
int my_port ;
fscanf(fp_conf, "%s%d", my_ip, &my_port);
close(fd_conf);
fclose(fp_conf); /* 创建服务器的监听socket端口 */
int fd_listen
fd_listen = socket(AF_INET, SOCK_STREAM, 0);
if(fd_listen == -1)
{
perror("socket");
} /* 为服务器socket端口绑定联系方式,以便让客户端connect */
struct sockaddr_in server_addr ;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET ;
server_addr.sin_port = htons(my_port);
server_addr.sin_addr.s_addr = inet_addr(my_ip);
if(-1 == bind(fd_listen, (struct sockaddr *)&server_addr, sizeof(server_addr)) )
{
perror("bind");
close(fd_listen);
exit(1);
}
/* listen */
if(-1 == listen(fd_listen, 5))
{
perror("listen");
close(fd_listen);
exit(1);
} /* accept */
int fd_client; /* 客户端socket端口的另一头 */
struct sockaddr_in client_addr ; /* 客户端联系方式,以accept函数的传出参数给出 */
int len ;
memset(&client_addr, 0, sizeof(client_addr));
len = sizeof(client_addr);
while(1)
{
fd_client = accept(fd_listen, (struct sockaddr *)&client_addr, &len);
if(fd_client == -1)
{
continue ;
}
printf("a client connect ! ip:port %s:%d\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
if(fork() == 0)
{
close(fd_listen); //对于子进程和孙子进程都不需要listen端口,直接关闭。
if(fork() == 0)
{ int fd_file = open(FILE_NAME, O_RDONLY); //打开客户端要下载的文件
char buf[SNDSIZE] ;
int snd_cnt = 0 ;
int readn ;
/* 从文件中读取数据,并发送给客户端 */
while(memset(buf, 0,SNDSIZE ), (readn = read(fd_file,buf, SNDSIZE)) > 0)
{
if(send(fd_client, buf, readn, 0) != readn)
{
printf("send error! \n");
}
snd_cnt ++ ;
}
printf("send over: %d \n", snd_cnt);
close(fd_file);
close(fd_client);
exit(0);
}
close(fd_client);
exit(0);
}
close(fd_client);
wait(NULL) ; } return 0 ;
}

client端

/*************************************************************************
> File Name: client.c
> Author: KrisChou
> Mail:zhoujx0219@163.com
> Created Time: Thu 28 Aug 2014 11:59:20 PM CST
************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#define SNDSIZE 1024*1024
#define SERVER_PORT 6080 // 服务器端口 int main(int argc, char *argv[]) EXE IP
{
/* socket */
int fd_client;
fd_client = socket(AF_INET, SOCK_STREAM, 0);
if(fd_client == -1)
{
perror("socket");
exit(1);
}
/* 存放所连服务器信息的结构体 */
struct sockaddr_in server_addr;
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
/* connect */
while(connect(fd_client, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1)
{
/* 当connect返回-1时,说明服务器还没有启动 */
sleep(1);
printf("connecting... \n");
}
printf("connect success! \n"); int fd_write = open("txt", O_WRONLY | O_CREAT);//下载的内容写入本地文件中
char buf[SNDSIZE];
int readn;
int recv_cnt = 0;
while(memset(buf,0,SNDSIZE),(readn = recv(fd_client,buf,SNDSIZE,0)) > 0)
{
write(fd_write,buf,readn);
recv_cnt++;
}
printf("recv over: %d \n", recv_cnt);
close(fd_write);
close(fd_client);
return 0;
}

Linux网络编程6——使用TCP实现文件服务器的更多相关文章

  1. Linux网络编程:基于TCP的程序开发回顾篇《转》

    面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你 ...

  2. 【深入浅出Linux网络编程】 “实践 -- TCP & UDP”

    通过上一篇博客的学习,你应该对基于epoll的事件触发机制有所掌握,并且通过阅读sio.c/sio.h应该也学会了如何封装epoll以及如何通过设计令epoll更加实用(用户回调,用户参数). 简单回 ...

  3. Linux网络编程--wireshark分析TCP包头的格式

    摘要:     本文简介了TCP面向连接理论知识,具体讲述了TCP报文各个字段含义.并从Wireshark俘获分组中选取TCP连接建立相关报文段进行分析. 一.概述     TCP是面向连接的可靠传输 ...

  4. Linux网络编程——浅谈 TCP 三次握手和四次挥手

    一.tcp协议格式 二.三次握手 在 TCP/IP 协议中.TCP 协议提供可靠的连接服务,採用三次握手建立一个连接. 第一次握手:建立连接时,client发送 syn 包(tcp协议中syn位置1. ...

  5. Linux网络编程二、tcp连接API

    一.服务端 1.创建套接字: int socket(int domain, int type, int protocol); domain:指定协议族,通常选用AF_INET. type:指定sock ...

  6. Linux网络编程9——对TCP与UDP的简易封装2.0

    具体生成动态库的操作及使用该动态库的操作请参见上篇博文.以下仅仅列出改进版本的代码. 代码 my_socket.h #ifndef __MY_SOCKET_H__ #define __MY_SOCKE ...

  7. Linux网络编程8——对TCP与UDP的简易封装

    引言 每次使用socket通信,都会有很对相似的操作.本文,会对TCP与UDP通信做一简单封装,并生成动态库. 代码 my_socket.h #ifndef __MY_SOCKET_H__ #defi ...

  8. 【Linux 网络编程】常用TCP/IP网络编程函数

    (1)函数socket /**************************************************************** ** 功能:创建一个套接字用于通信 ** 参 ...

  9. Linux网络编程7——使用TCP实现双方聊天

    思路 主线程负责发送消息,另一线程负责接收消息.服务端和客户端均是如此. 注意 当A方close掉用于通信的socket端口后,该端口是不会立即关闭的.因为此时可能B方的信息还没send完.因此,此时 ...

随机推荐

  1. hdu 5253 连接的管道

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5253 连接的管道 Description 老 Jack 有一片农田,以往几年都是靠天吃饭的.但是今年老 ...

  2. iOS-CALayer

    iOS开发UI篇—CAlayer层的属性 一.position和anchorPoint 1.简单介绍 CALayer有2个非常重要的属性:position和anchorPoint @property ...

  3. Java中的访问权限

    Java中有四种访问权限,从大到小依次是:public –> protected –> default(friendly) –> private. 简单说明下: public 作用域 ...

  4. 条款11:在operator=中处理“自我赋值”

    什么是自我赋值,就是 v = v 这种类型的语句,也许很多人都会说鄙视这种写法,但是如下的写法会不会出现呢? 比如:a[i] = a[j];      // 不巧的是i可能和j相等 *px = *py ...

  5. [转]ldconfig几个需要注意的地方

    [转]ldconfig几个需要注意的地方 http://www.cnblogs.com/arci/archive/2011/03/19/1988952.html 1. 往/lib和/usr/lib里面 ...

  6. 单行bash、shell、perl命令

    主题:单行经典bash.shell.perl命令 作者:luomg 摘要: 会陆陆续的写自己工作中的常用有意思的命令,争取你能看完后就能搞定常见操作, 且尽量自少提供基本shell.perl的实现方式 ...

  7. python pandas/numpy

    import pandas as pdpd.merge(dataframe1,dataframe2,on='common_field',how='outer') replace NaN datafra ...

  8. vhdl基础---分频

    偶数分频 ibrary IEEE; use IEEE.STD_LOGIC_1164.ALL; use ieee.std_logic_arith; use ieee.std_logic_unsigned ...

  9. 20145120 《Java程序设计》第6周学习总结

    20145120 <Java程序设计>第6周学习总结 教材学习内容总结 java.io.InputStream.java.io.OutputStream实例分别作为输入.输出串流的代表对象 ...

  10. 结队开发项目——基于Android的无线点餐系统——NABC模型

    特点:通过提前订餐,可以节约学生大量的排队时间. N(need):生活中可以发现许多同学都喜欢出去买饭,而且在有的摊位需要排很长时间的队,这样他们就会很晚吃到饭,下午有课的学生都不能睡午觉,所以通过我 ...