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


    需求

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

    思路

    服务器端,主进程负责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
    ",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! 
    ");
                            }
                            snd_cnt ++ ;
                    }
                    printf("send over: %d 
    ", 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... 
    ");
        }
        printf("connect success! 
    ");
    
        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 
    ", recv_cnt);
        close(fd_write);
        close(fd_client);
        return 0;
    }
  • 相关阅读:
    Tomcat下bootstrap启动分析
    Ubuntu读取/root/.profile时发现错误:mesg:ttyname fa
    【转载】Activiti delete process definition by key
    Ubuntu16解锁root
    Activiti源码:ActivitiEventSupport类中eventListeners的设计
    [转载] Activiti Tenant Id 字段释疑
    Linux下使用NTFS格式移动硬盘
    Linux dd命令制作U盘启动盘
    Activiti源码:StandaloneInMemProcessEngineConfiguration与SpringProcessEngineConfiguration
    Activiti源码学习:ExecutionListener与TaskListener的区别
  • 原文地址:https://www.cnblogs.com/jianxinzhou/p/3947527.html
Copyright © 2020-2023  润新知