客户端传文件给服务器端

要求:利用TCP Socket实现PC机与目标板的通讯,PC机为服务器,目标板为客户端,服务器可同时接受多个客户端连接。

解:

使用方法:

一:两台linux虚拟机之间
服务器:

1:     gcc server.c -o server -lpthread

2:    ./server


客户端:

1:     gcc client.c -o client

2:     ./client 服务器端ip地址   例如:./client 192.168.20.131

3:     输入要发送给服务器端的文件名


二:ubuntu虚拟机与arm学习板
1:     虚拟机上运行   gcc server.c -o server -lpthread
2:     虚拟机上运行   arm-linux-gcc client.c -o client
3:     将client复制到arm学习板上后,再学习板上执行命令 chmod 777 client

扫描二维码关注公众号,回复: 2520666 查看本文章

4:     虚拟机上运行./server
5:     在arm学习板上运行    ./client 服务器端ip地址    例如:./client 192.168.20.131
6:    输入要发送给服务器端的文件名

/*server.c*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>//线程的头文件
#define PORT            54321
#define BUFFER_SIZE        2048
#define MAX_BACKLOG    5  //连接请求队列最大长度
#define MAX_CONNECT 5 //服务器允许同时连接的最大客户端数量

pthread_t thread_id[MAX_CONNECT]={};

typedef struct name 
{
    char counter_id;
    int _client_fd;
//    struct sockaddr_in _client_sockaddr;
}A_struct; 

/*******多线程任务*******/
void *Client_Process(void *arg)
{
    A_struct a;
    a=*(struct name *)arg;
    
    char file_name[BUFFER_SIZE]={};
    if(recv(a._client_fd,file_name,sizeof(file_name),0)<0)  //接收文件名
    {
        printf("Local: Server Recieve File Name Failed!(client %d ) \n",a._client_fd);   //接收数据失败
        printf("Local: 断开 client %d 连接\n",a._client_fd);
        send(a._client_fd,"exit",4,0);  //发送exit    
        usleep(100000);
        close(a._client_fd); //关闭与客户端的连接
        thread_id[a.counter_id]=0;
        return;
    }
    printf("Local: Receive file name from client %d : %s \n",a._client_fd,file_name);
    
    FILE *fp=fopen(file_name,"w");  //创建文件写入
    if(NULL==fp)    //新建或打开文件进行写操作失败
    {
        printf("Local: File %s Can Not Open To Write! (client %d ) \n",file_name,a._client_fd);   
        printf("Local: 断开 client %d 连接\n",a._client_fd);
        send(a._client_fd,"exit",4,0);  //发送exit    
        usleep(100000);
        close(a._client_fd); //关闭与客户端的连接
        thread_id[a.counter_id]=0;
        return;
    }
    
    char buffer[BUFFER_SIZE]={};
    int length=0;
    while((length=recv(a._client_fd,buffer,sizeof(buffer),0)) >0)   //将从客户端接收数据缓存到buffer中
    {        //每接收一段数据,便将其写入文件中,循环直到文件接收并写完为止
        if(fwrite(buffer,sizeof(char),length,fp)<length) 
        {    //如果实际写入的字节数少于客户端传来的字节数,则写入错误
            printf("Local: File %s Write Failed! (client %d ) \n",file_name,a._client_fd);//文件写入失败
        //    break;
        
            fclose(fp);   //关闭文件
            printf("Local: 断开 client %d 连接\n",a._client_fd);
            send(a._client_fd,"exit",4,0);  //发送exit    
            usleep(100000);
            close(a._client_fd); //关闭与客户端的连接
            thread_id[a.counter_id]=0;
            return;
        }
        bzero(buffer,sizeof(buffer));   //将buffe清零
    }
    printf("Local: Receive File: %s  (client %d ) \n",file_name,a._client_fd);  //从服务器得到文件:%s
    fclose(fp);   //关闭文件
    
    printf("Local: 断开 client %d \n",a._client_fd);
    send(a._client_fd,"exit",4,0);  //发送exit    
    usleep(100000);
    close(a._client_fd); //关闭与客户端的连接
    thread_id[a.counter_id]=0;    
}

/******主函数********************/
int main( )
{
    struct sockaddr_in server_sockaddr,client_sockaddr;
    int sockfd,client_fd;
    
    /*建立socket连接*/
    if ((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1)
    {
        perror("Create Socket Failed! \n");//创建套接字失败
        exit(1);
    }
    
    /*设置sockaddr_in 结构体中相关参数*/
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT);
    server_sockaddr.sin_addr.s_addr = INADDR_ANY;
    socklen_t len = sizeof(server_sockaddr);
    bzero(&(server_sockaddr.sin_zero), 8);
    
    int opt = 1;/* 允许重复使用本地地址与套接字进行绑定 */
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    
    /*绑定函数bind()*/  //将套接字绑定一个IP地址和端口号
    if (bind(sockfd, (struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr)) == -1)
    {
        perror("Server Bind Failed! 端口被占用 \n"); //套接口与本地ip地址和端口绑定失败
        close(sockfd);
        exit(1);
    }
    
    /*调用listen()函数,创建未处理请求的队列*/
    if (listen(sockfd, MAX_BACKLOG) == -1)
    {
        perror("Server Listen Failed! \n");   //套接字设置为监听状态失败
        close(sockfd);
        exit(1);
    }
    printf("Listening....\n");
    
    while(1)
    {
        /*调用accept()函数,阻塞等待客户端的连接请求*/
        if ((client_fd = accept(sockfd,(struct sockaddr *)&client_sockaddr, &len)) == -1)
        {
            perror("Server Accept Failed! \n");   //接受连接失败
            close(sockfd);
            exit(1);
        }
        char j;
        for(j=0;j<MAX_CONNECT;j++)
        {
            if(thread_id[j]==0)
            {
                A_struct temp;
                temp.counter_id=j;
                temp._client_fd=client_fd;
//                temp._client_sockaddr=client_sockaddr;
                
                pthread_create(&thread_id[j],NULL,Client_Process,(void *)&temp);
                printf("Local: client %d 连接\n",client_fd);
                usleep(1000);
                break; //成功创建线程则退出循环
            }
        } 
        if(j==MAX_CONNECT) //线程满
        {
            char buf1[]="连接达最大上限,请稍后再连接!";
            send(client_fd,buf1,strlen(buf1),0);  //将buf1的数据发送到套接口
            usleep(100000);  //100ms
            send(client_fd,"exit",4,0);  
            usleep(100000);  //100ms,等待发完,再关闭client_fd
            close(client_fd);
        }
    }
    
    printf("Local: 退出 \n");
    close(sockfd);//关闭监听用的socket
    return 0;     //正常退出    
}

/*client.c*/

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
//#include <pthread.h>//线程的头文件

#define SERVER_PORT 54321
//#define CLIENT_PORT 6543
#define SEND_BUFFER_SIZE 1024
//#define RECV_BUFFER_SIZE 2048

/******主函数********************/
int main(int argc, char *argv[])
{
    int sockfd;
    struct hostent *host;
    struct sockaddr_in server_sockaddr;
    //struct sockaddr_in client_sockaddr;
    
    if(argc != 2 )
    {
        fprintf(stderr,"Usage: %s Hostname(or ip address) \n",argv[0]);
        return -1;
    }
    /*地址解析函数*/
    if ((host = gethostbyname(argv[1])) == NULL)
    {
        perror("Server IP Address Error. \n");
        return -1;
    }
    
    /*创建socket*/
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("Create Socket Failed! \n");//创建Socket失败
        return -1;
    }    
    /*设置客户端相关参数*/
/*    
    client_sockaddr.sin_family = AF_INET;
    client_sockaddr.sin_port = htons(CLIENT_PORT);
    client_sockaddr.sin_addr.s_addr = INADDR_ANY; // 允许所有人链接我
    
    int opt=1; // 允许重复使用本地地址与套接字进行绑定 
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
*/    
    /*绑定函数bind()*/  //将套接字绑定一个IP地址和端口号
/*
    if (bind(sockfd, (struct sockaddr *)&client_sockaddr,sizeof(struct sockaddr)) == -1)
    {
        perror("Server Bind Failed! 端口已经被占用\n"); //套接口与本地ip地址和端口绑定失败
        close(sockfd);
        return -1;
    }
*/
    /*设置sockaddr_in 服务器端结构体中相关参数*/
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(SERVER_PORT);
    server_sockaddr.sin_addr = *((struct in_addr *)host->h_addr);
    bzero(&(server_sockaddr.sin_zero), 8);
    /*调用connect函数主动发起对服务器端的连接*/
    if(connect(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr))== -1)
    {
        perror("Connect To Server IP Failed! \n"); //连接服务器失败
        close(sockfd);    //关闭Socket
        return -1;
    }

/////////////////////////////////////////////////////
    char file_name[SEND_BUFFER_SIZE]={};
    FILE *fp;
    printf("Connected! \n");
    printf("please input file name:\n");
    
    do
    {
        bzero(file_name,sizeof(file_name)); //清零
        scanf("%s",file_name);
        fp=fopen(file_name,"r");  //打开文件准备读取文件
        if(NULL==fp)
        {
            printf("Not Found %s \n",file_name);   //没有找到文件
            printf("Please input file name again:\n");
        }
    }while(NULL==fp);
    
    if(send(sockfd,file_name,strlen(file_name),0)<0)   //将文件名发送给服务器
    {
        printf("Send file name \" %s \" failed. \n",file_name);
        fclose(fp);   //关闭文件
        close(sockfd);    //关闭套接口
        return -1;
    }
    usleep(10000);//延时10ms,一定要延时,不然文件名和数据会连在一起发送
    char buffer[SEND_BUFFER_SIZE]={};
    int length=0;
    //每读取一段数据,便将其发送给服务器,循环直到文件读完为止
    while((length=fread(buffer,sizeof(char),sizeof(buffer),fp))>0)   //读取数据并缓存到buffer中
    {
        if(send(sockfd,buffer,length,0)<0)   //将buffer的数据发送到套接口
        {
            printf("Send File %s Failed. \n",file_name);//发送文件失败
            fclose(fp);   //关闭文件
            close(sockfd);    //关闭套接口
            return -1;
        }
        bzero(buffer,sizeof(buffer));  //将buffer清零
    }
    
    fclose(fp);//关闭文件
    printf("File:%s  Transfer Successful! \n",file_name);
    close(sockfd);    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Chenger_32123/article/details/81332171