需求

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

思路

服务器端,主进程负责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. Tutorial: Importing and analyzing data from a Web Page using Power BI Desktop

    In this tutorial, you will learn how to import a table of data from a Web page and create a report t ...

  2. linux新增一块硬盘加入原有分区

    原有硬盘空间已经不足,添加一块新硬盘,并且加入到原根目录下 查看新硬盘 1 2 fdisk -l Disk /dev/sdb: 240.1 GB, 240057409536 bytes 在新硬盘上创建 ...

  3. vc++编程之在程序中加入网址链接

    在vc++对话框编程中,我们处于某种需要(介绍自己的软件或者自己的博客)可以在对话框上增加一个网址链接,用户只要一点击,就进入了相应的网页,我在此演示下如何完成. 1 打开编译器,我们新建一个基于对话 ...

  4. 桥接模式和NAT模式

    linux的目录结构 配置ip三种 模式 桥接模式 nat模式(VMnet8) 配置网关 DHCP动态分配IP设置 linux的目录结构 配置ip三种 模式 桥接模式 (1) 设置主系统的" ...

  5. TI IPNC Web网页之流程分析

    流程 Appro IPNC使用的web服务器是boa. 请仔细理解下面这段话. boa这个web服务器是GUI界面和IPNC应用程序之间的通信的桥梁.它的责任是从web GUI中接收HTTP请求,并且 ...

  6. html标记列表应用

    一.[ul]无序列表 1.无序列表====== 二.[ol]有序列表 1.有序列表用于段落有序的排列, <ol> <li>内容</li> </ol> 三 ...

  7. 什么是锚点(AnchorPoint)

    1.锚点通常是图形的几何中心, AnchorPoint(x,y)的两个参量x和y的取值通常都是0到1之间的实数,表示锚点相对于节点长宽的位置. 例如,把节点左下角作为锚点,值为(0,0): 把节点的中 ...

  8. Asp.Net MVC3(三)-MvcApp实现全局异常捕获

    定义异常捕获类: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMu ...

  9. Elasticsearch 权威指南 NESTAPI地址

    Elasticsearch 权威指南:http://fuxiaopang.gitbooks.io/learnelasticsearch/content/index.html NEST:http://n ...

  10. MySQL 主从数据库设置

    1.复制的介绍 MySQL 支持单向.异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器.主服务器将更新写入二进制日志文件,并维护文件的一个索引 以跟踪日志循环.这些日志可 ...