Linux网络编程6——使用TCP实现文件服务器

需求

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

思路

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

代码

server端

/*************************************************************************

  > File Name: server.c

  > Author: KrisChou

  > Mail:[email protected] 

  > 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:[email protected] 

    > 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)