需求

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

思路

服务器端,主进程负责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. 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统 :1.技术简介之Mina连接

    欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 Apache MINA(Multipurpose Infrastructure for Network Applic ...

  2. Android的快速开发框架afinal

    afinal 是一个android的 orm 和 ioc 框架.而且封装了android中的httpClient,使其更加简单易用. afinal是android应用开发的终极框架. FinalDB使 ...

  3. php判断来源网址地址并且限制非法来源

    $fromHost = array( 'paipai.com', 'localhost', '127.0.0.1' ); $s = 'http://www.paipai.Com/chong/abc.s ...

  4. 008--VS2013 C++ 位图半透明化(另一种显示)

    注:主要变化是在下面这张位图上的操作 //全局变量HBITMAP bg, girl;HDC mdc;//起始坐标const int xstart = 50;const int ystart = 20; ...

  5. SQLite数据库的基本API函数

    1 .打开数据库: 说明:打开一个数据库,文件名不一定要存在,如果此文件不存在, sqlite 会自动创建.第一个参数指文件名,第二个参数则是定义的 sqlite3 ** 结构体指针(关键数据结构), ...

  6. 桥接模式和NAT模式

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

  7. chart.js图表库案例赏析,饼图添加文字

    chart.js图表库案例赏析,饼图添加文字 Chart.js 是一个令人印象深刻的 JavaScript 图表库,建立在 HTML5 Canvas 基础上.目前,它支持6种图表类型(折线图,条形图, ...

  8. 网络---中断套接字Socket

    package socketpack_2; import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.even ...

  9. 【Binary Tree Maximum Path Sum】cpp

    题目: Given a binary tree, find the maximum path sum. The path may start and end at any node in the tr ...

  10. Oracle创建表时涉及的参数解析

    1.oracle pctfree和pctused详解   http://www.cnblogs.com/linjiqin/archive/2012/01/16/2323320.html http:// ...