• linux c做服务端使用多线程接收图片并且将图片写入数据库


    #include<sys/socket.h>
    #include<sys/types.h>
    #include<sys/stat.h>//包含文件的全部结构,属性
    #include<stdlib.h>
    #include<stdio.h>
    #include<string.h>
    #include<unistd.h>
    #include<error.h>
    #include<netinet/in.h>
    #include<arpa/inet.h>
    #include<pthread.h>
    #include<sys/time.h>
    #include<sqlite3.h>
    
    #define   SER_PORT      1900
    #define   MAX_LEN       256
    #define FILENAME_LENGTH  32
    
    int     listensd,connectsd;
    char    buf[MAX_LEN] = " ";
    char flag[MAX_LEN]=" ";
    pthread_t thread[3];
    int threadnum=3;
    sqlite3 *db=0;
    char * pErrMsg;//保存返回数据库错误
    
    //数据库查询回调函数定义
    int select_callback(void * data, int col_count, char ** col_values, char ** col_Name)
    {
      // 每条记录回调一次该函数,有多少条就回调多少次
      int i;
      for( i=0; i < col_count; i++){
        printf( "%s = %s
    ", col_Name[i], col_values[i] == 0 ? "NULL" : col_values[i] );
        printf("
    ");
      }
    
      return 0;
    }
    
    //次回调函数用于查询数据库的所有图片并且把每一项的url解析并且发送给客户端
    int select_callback_send(void *data,int col_count,char **col_values,char** col_name){
        int i;
        FILE *fp=NULL;
        int len_send;
        char *buf_time=" ";
        for(i=0;i<col_count;i++){
            printf("%s=%s=n",col_name[i],col_values[i]==0?"NULL":col_values[i]);
            //发送插入时间
            if(strcmp("[InsertTime]",col_name[i])==0){
                buf_time=col_name[i];
                if(write(connectsd,buf_time,sizeof(buf_time))<0){
                    perror("buf_time write error:
    ");
                }
            //发送图片
            if(strcmp("[url]",col_name[i])==0){
                if((fp=fopen(col_name[i],"ab"))==NULL){
                    perror("file open error");
                }else{
                    while(!feof(fp)){
                        len_send=fread(buf,1,MAX_LEN,fp);
                        if(len_send!=write(connectsd,buf,len_send)){
                            perror("write");
                        }
                    }
                }
                printf("图片%s发送成功!",col_name[i]);
            }
        }
    }
    
    //线程函数定义
    int *threadf(){
        int con_copy=connectsd;
        int len;
        FILE *fp=NULL;
        FILE *fp1=NULL;
        int status=0;
        char filename[FILENAME_LENGTH]=" ";
        char sql[100]=" ";//这里使用数组或者是字符指针都是一样的到时候传入的都是名字即首地址
        bzero(flag,sizeof(flag));
        read(con_copy,flag,MAX_LEN);
        printf("flag:");
        fputs(flag,stdout);
        printf("
    ");
        //服务端接收图片
        // bzero(flag,sizeof(flag));
        bzero(buf,sizeof(buf));
        if(strcmp(flag,"send
    ")==0){
            snprintf(filename,FILENAME_LENGTH,"%d.jpg",threadnum);
            if((fp=fopen(filename,"ab"))==NULL){
                perror("File open");
                //close(listensd);
                exit(1);
            }
            while(1){
                len=read(con_copy,buf,MAX_LEN);
                if(len<0){//加上该错误判断就能保证在出错时能正确退出
                    perror("read");
                    exit(1);
                }
                if(len==0){
                    break;
                } 
                fwrite(buf,1,len,fp);
            }
            //写入数据库
            snprintf(sql,100,"insert into pic([picId],[url]) values(null,'%s')",filename);
            if(sqlite3_exec(db,sql,0,0,&pErrMsg)!=SQLITE_OK){
                fprintf(stderr,"insert sql error:%s
    ",pErrMsg);
                sqlite3_free(pErrMsg);
            }else{
                printf("插入数据成功
    ");
                //每一次插入成功都使用查询显示当前的数据库状态
                printf("开始查询数据:
    ");
                if(sqlite3_exec( db, "select * from pic;", select_callback, 0, &pErrMsg)!=SQLITE_OK){
                    fprintf(stderr, "select SQL error: %s
    ", pErrMsg);
                }else{
                    printf("查询成功! 
    ");
                }
            }
            printf("the pic %d is accept suc!
    ",threadnum);
            close(con_copy);
            fclose(fp);
            return 0;
        //服务端发送图片(先从数据库查询可用数据,找到相应的url依次打开并且发送给客户端)
        }else if(strcmp(flag,"rec
    ")==0){
                if( ( fp1 = fopen("client.jpg","rb") ) == NULL )
                {
                   perror("File open");
                   //close(listensd);
                   exit(1);
                }
                while( !feof(fp1) )
                {
                    len = fread(buf,1,MAX_LEN,fp1);//从文件fq中读取MAX_LEN个字段每个字段长度为1并且给buf
                    if( len != write(con_copy,buf,len) )
                    {
                            perror("write");
                            break;
                    }
                }
                close(con_copy);
                //close(listensd);
                fclose(fp1);
                return 0;
        }else{
            return 0;
        }
        
        // if(!mkdir(filename,0777)){
            // printf("创建目录失败");
        // }
        // snprintf(filename,FILENAME_LENGTH,"//1.jpg");
    
        // if(SQLITE_OK!=sqlite3_open("pic.db",&db)){
            // fprintf(stderr,"无法连接数据库:%s",sqlite3_errmsg(db));
            // exit(1);
        // }
        // if(SQLITE_OK!=sqlite3_exec(db,"insert into pic(url) values("test.jpg")",0,0,&pErrMsg));
        // {
            // fprintf(stderr,"无法插入数据:%s",sqlite3_errmsg(db));
            // exit(1);
        // }
    }
    
    //初始化数据库,包括创建库和表
    void initDb(){
        char * createtablesql=
        "create table pic([picId] integer PRIMARY KEY AUTOINCREMENT, [InsertTime] TimeStamp NOT NULL DEFAULT (datetime('now','localtime')), [url] varchar(20))";
        if(sqlite3_open("pic.db",&db)!=SQLITE_OK){
            fprintf(stderr,"无法打开数据库:%s",sqlite3_errmsg(db));
        }else{
            printf("数据库创建成功!
    ");
        }
        if(sqlite3_exec(db,createtablesql,0,0,&pErrMsg)!=SQLITE_OK){
            fprintf(stderr, "无法创建数据表:%s
    ", pErrMsg);
        }else{
            printf("建表成功!
    ");
        }
    }
    
    int main(int argc,char **argv)
    {
            struct sockaddr_in   server;
            struct sockaddr_in   client;
            FILE    *fp;
            int     opt = 1;
            if( ( listensd = socket(AF_INET,SOCK_STREAM,0) ) == -1 )
            {
                    perror("socket");
                    exit(1);
            }
            setsockopt(listensd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
            bzero(&server,sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(SER_PORT);
            server.sin_addr.s_addr = htonl(INADDR_ANY);
             if( bind(listensd,(struct sockaddr *)&server,sizeof(server)) < 0)
            {
                    perror("Bind");
                    close(listensd);
                    exit(1);
            }
             if( listen(listensd,5) == -1 )
            {
                    perror("listen");
                    close(listensd);
                    exit(1);
            }
            initDb();
            while( 1 )         
            {
                    int   rn ;
                    int   sin_len = sizeof(client);
                    //accept为阻塞,一直等到有客户端连接到时候才会进行并且往下执行,多线程中每一次新的线程建立的时候都是一个新的连接
                    if( (connectsd = accept(listensd,(struct sockaddr *)&client,&sin_len)) < 0 )
                    {
                            perror("accept");
                            continue;
                    }
                    printf("新连接建立!");
                    if(threadnum<10){
                        pthread_create(&thread[threadnum],NULL,threadf,NULL);
                        pthread_detach(&thread[threadnum]);//分离子线程和主线程
                        printf("客户端%d已经开始传输数据!
    ",threadnum);
                        threadnum++;
                    }else{
                        printf("threadsize over!
    ");
                        close(listensd);
                        break;
                    }
            }
            // int i=0;
            // for(i;i<threadnum;i++){//等待所有已经创建的线程结束后才结束该进程
                // pthread_join(thread[i],NULL);
                // printf("线程%d已经加入等待
    ",i);
            // }
            close(listensd);
            return   0;
    }  
  • 相关阅读:
    Scrapy的架构与原理的理解【转】
    Scrapy框架的命令行详解【转】
    WPF 程序中启动和关闭外部.exe程序
    C++ 二维数组(双重指针作为函数参数)
    C++ 遇见的一些函数
    C++ #pragma 预处理指令
    C++异常处理(Exception Handling)
    C++模板学习随笔
    C++ 数组的地址问题学习随笔
    关于C++几个容易混淆的概念总结
  • 原文地址:https://www.cnblogs.com/zzy-frisrtblog/p/5778998.html
Copyright © 2020-2023  润新知