• linux 仿QQ 2.0版本


    这个版本对上一个版本进行了一些更改,实现了服务端–>客户端,客户端–》客户端,但是并不算是很友好,此版本还是保留在本地上的传输,下一个版本将会在不同ip地址下面的传输(前提是在同一个局域网),我想在下一个版本实现跨平台,同时实现客户端到服务端和客户端的文件传输

    具体的表结构看我的第一个版本(Linux 应用程序中)

    客户端的代码:
    main.c

    /*
     * 1.2
     编译:gcc view.c -o view `pkg-config --cflags --libs gtk+-2.0`
     */
    
    #include<gtk/gtk.h>  
    #include <stdio.h>  
    #include <stdlib.h> 
    #include <unistd.h>
    #include "view.h"
    
    static GtkWidget* entry1;  
    static GtkWidget* entry2;  
    
    GtkWidget* window; 
    
    void on_button_clicked (GtkWidget* button,gpointer data)  
    {  
        /*void gtk_entry_set_text(Gtk_Entry *entry,const gchr  *text) 
             *     将新的内容取代文本输入构件当前的内容。 
             *const gchar *gtk_entry_get_text(GtkEntry *entry) 
             *     获得当前文本输入构件的内容 
             */  
            if((int)data == 1){  
                gtk_entry_set_text(GTK_ENTRY(entry1),"");  
                gtk_entry_set_text(GTK_ENTRY(entry2),"");  
            } 
        else if ((int)data == 2){  
                const gchar* username = gtk_entry_get_text(GTK_ENTRY(entry1));  
                const gchar* password = gtk_entry_get_text(GTK_ENTRY(entry2)); 
    
            mydb_init();
            if(mydb_test(mysql,username,password)==1)
            {
            if(write_to_file("login success!")==0)
            {
                exit(-1);
            }
            mydb_destory(mysql);
              //登陆到客户端窗口程序
              execv("./client", NULL);
            }
            else
            {
                if(write_to_file("login failed!")==0)
            {
                exit(-1);
            }
            exit(-1);
            }  
            } 
        else if((int)data == 3){  
                /*改变文本空的可编辑状态*/  
                gtk_editable_set_editable(GTK_EDITABLE(entry1),GTK_TOGGLE_BUTTON(button)->active);  
                gtk_editable_set_editable(GTK_EDITABLE(entry2),GTK_TOGGLE_BUTTON(button)->active);  
            }  
    }  
    
        int main(int argc,char* argv[])  
        {   
            GtkWidget* box;  
            GtkWidget* box1;  
            GtkWidget* box2;  
            GtkWidget* box3;  
            GtkWidget* label1;  
            GtkWidget* label2;  
            GtkWidget* button;  
            GtkWidget* sep;  
            //初始化  
            gtk_init(&argc,&argv);  
            //设置窗口  
            window = gtk_window_new(GTK_WINDOW_TOPLEVEL);  
            g_signal_connect(GTK_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(closeApp),NULL);  
            gtk_window_set_title(GTK_WINDOW(window),"登录窗口");  
            gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);  
            gtk_container_set_border_width(GTK_CONTAINER(window),20);  
    
            box = gtk_vbox_new(FALSE,0);  
            gtk_container_add(GTK_CONTAINER(window),box);  
            box1 = gtk_hbox_new(FALSE,0);  
            gtk_box_pack_start(GTK_BOX(box),box1,FALSE,FALSE,5);  
            box2 = gtk_hbox_new(FALSE,0);  
            gtk_box_pack_start(GTK_BOX(box),box2,FALSE,FALSE,5);  
            sep = gtk_hseparator_new();//分割线  
            gtk_box_pack_start(GTK_BOX(box),sep,FALSE,FALSE,5);  
            box3 = gtk_hbox_new(FALSE,0);  
            gtk_box_pack_start(GTK_BOX(box),box3,TRUE,TRUE,5);  
    
    
            label1 = gtk_label_new("用户名:");  
            entry1 = gtk_entry_new();  
            gtk_box_pack_start(GTK_BOX(box1),label1,FALSE,FALSE,5);  
            gtk_box_pack_start(GTK_BOX(box1),entry1,FALSE,FALSE,5);  
    
            label2 = gtk_label_new("密    码:");  
            entry2 = gtk_entry_new();  
            /*设置输入文本不可见*/  
            gtk_entry_set_visibility(GTK_ENTRY(entry2),FALSE);  
            gtk_box_pack_start(GTK_BOX(box2),label2,FALSE,FALSE,5);  
            gtk_box_pack_start(GTK_BOX(box2),entry2,FALSE,FALSE,5);  
    
            button = gtk_check_button_new_with_label("Editable");  
            g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(on_button_clicked),(gpointer)3);  
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),TRUE);  
            gtk_box_pack_start(GTK_BOX(box3),button,TRUE,TRUE,10);  
            gtk_widget_show(button);  
    
            button = gtk_button_new_with_label("清空");  
            g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(on_button_clicked),(gpointer)1);  
            gtk_box_pack_start(GTK_BOX(box3),button,TRUE,TRUE,10);  
            gtk_widget_show(button);  
    
            button = gtk_button_new_with_label("确认");  
            g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(on_button_clicked),(gpointer)2);  
            g_signal_connect_swapped(G_OBJECT(button),"clicked",G_CALLBACK(gtk_widget_destroy),window);  
            gtk_box_pack_start(GTK_BOX(box3),button,TRUE,TRUE,5);  
            gtk_widget_show(button);  
    
    
            gtk_widget_show_all(window);  
            gtk_main();  
            return 0;  
        } 

    view.h:

    /*
     * 1.2
     编译:gcc view.c -o view `pkg-config --cflags --libs gtk+-2.0`
     */
    #include <gtk/gtk.h>
    #include <stdio.h>
    #include "mydb.h"
    
    GtkWidget *username_entry,*password_entry;
    
    GtkWidget *vbox;
    
    int write_to_file(char *name)
    {   
        FILE *fp;
        char buffer[50];
        time_t timep;
        char time_buffer[100];
    
        fp=fopen("client.log","a+");
        if(fp==NULL)
        {
            exit(-1);
        }   
    
        sprintf(buffer,"%s
    ",name);
        if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
        {
            return 0;
        }
    
        time (&timep);
        sprintf(time_buffer,"%s
    ",ctime(&timep));
        if(fwrite(time_buffer,sizeof(char),strlen(time_buffer),fp)<=0)
        {
            return 0;
        }       
    
        fclose(fp);
        return 1;
    }
    
    void closeApp(GtkWidget *window,gpointer data)
    {
      mydb_destory(mysql);
      gtk_main_quit();
    } 

    mydb.h:

    #include <mysql.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    MYSQL *mysql;
    
    void mydb_init()
    {
      unsigned int timeout=5;
      int ret=0;
    
      mysql=mysql_init(NULL);
      if(mysql==NULL)
      {
        fprintf(stderr,"Mysql_init failed
    ");
        return;
      }
    
      ret=mysql_options(mysql,MYSQL_OPT_CONNECT_TIMEOUT,(const char *)&timeout);
      if(ret!=0)
      {
        fprintf(stderr,"set timeout error
    ");
        return;
      }
    
      mysql=mysql_real_connect(mysql,"localhost","user","passwd","qq",0,NULL,0);
      if(mysql){
        printf("connection success
    ");
      }else{
        fprintf(stderr,"connection failed
    ");
        if(mysql_errno(mysql)){
          fprintf(stderr,"Connection error %d: %d
    ",mysql_errno(mysql),mysql_error(mysql)); 
        }
        return;
      }
    }
    
    int mydb_insert(MYSQL *mysql,void *user,void *password)
    {
      int ret=0;
      /*
      int *a=(int)user;
      int res=*a;
      */
      char* user_data=(char *)user;
      char* pswd_data=(char *)password;
      char qs[100];
    
      if(mysql==NULL){
        fprintf(stderr,"Mysql error
    ");
        return 0;
      }
    
      sprintf(qs,"insert into children(name,password) values('%s','%s')",user_data,pswd_data);
      ret=mysql_query(mysql,qs);
      if(!ret){
        printf("inserted %lu rows
    ",(unsigned long)mysql_affected_rows(mysql));
      }
      else
      {
        fprintf(stderr,"insert error %d: %s
    ",mysql_errno(mysql),mysql_error(mysql));
      }
    
      return 1;
    }
    
    int mydb_update(MYSQL *mysql,void *user,void *password)
    {
      int ret=0;
    
      char* user_data=(char *)user;
      char* pswd_data=(char *)password;
      char qs[100];
    
      if(mysql==NULL){
        fprintf(stderr,"Mysql error
    ");
        return 0;
      }
      sprintf(qs,"update children set password='$pswd_data' where name='%s'",user_data);
      ret=mysql_query(mysql,qs);
      if(!ret){
        printf("update %lu rows
    ",(unsigned long)mysql_affected_rows(mysql));
      }
      else
      {
        fprintf(stderr,"update error %d: %s
    ",mysql_errno(mysql),mysql_error(mysql));
      }
    
      return 1;
    }
    
    int mydb_search(MYSQL *mysql,void *data)
    {
       MYSQL_RES *res_ptr;
       MYSQL_ROW sqlrow;
       int res;
       char *user_data=(char *)data;
       const char *tmp='';
       char qs[100];
    
      if(mysql==NULL)
      {
        fprintf(stderr,"mysql error
    ");
        return 0;
      }
    
      sprintf(qs,"select name,password from children where name='%s'",user_data);
      res=mysql_query(mysql,qs);
      if(res)
      {
        printf("select error:%s
    ",mysql_error(mysql));
        return 0;
      }
      else
      {
        res_ptr=mysql_store_result(mysql);
        if(res_ptr){
          printf("Search to %lu rows
    ",(unsigned long)mysql_num_rows(res_ptr));
    
          while(sqlrow=mysql_fetch_row(res_ptr)){
        printf("Fetched data...
    ");
        tmp=(const char *)&sqlrow[1];
        if(strstr(tmp,user_data)==NULL)
        {
          printf("not exist!
    ");
          return 0;
        }
          }
          if(mysql_errno(mysql)){
        fprintf(stderr,"Retrive error: %s
    ",mysql_error(mysql));
          }
          mysql_free_result(res_ptr);
        }
      }
      return 1;
    }
    
    int mydb_test(MYSQL *mysql,const void * username_text,const void *  password_text)
    {
      MYSQL_RES *res_ptr;
      const char *username=(char *)username_text;
      const char *password=(char *)password_text;
      int res;
      unsigned long res_num;
      char qs[100];
    
      if(mysql==NULL)
      {
        fprintf(stderr,"mysql error
    ");
        return 0;
      }
    
      sprintf(qs,"select childno from children where name='%s' and password='%s'",username,password);
    
      res=mysql_query(mysql,qs);
      if(res)
      {
        printf("select error:%s
    ",mysql_error(mysql));
        return 0;
      }
     else
      {
        res_ptr=mysql_store_result(mysql);
        if(res_ptr){
          res_num=(unsigned long)mysql_num_rows(res_ptr);
          printf("res_num: %d
    ",res_num);
          if(res_num==0)
          {
        return 0;
          }
          else
          {
        printf("Search to %lu rows
    ",(unsigned long)mysql_num_rows(res_ptr));
          }
    
          if(mysql_errno(mysql)){
        fprintf(stderr,"Retrive error: %s
    ",mysql_error(mysql));
          } 
        }
        mysql_free_result(res_ptr);
      }
      return 1;
    }
    
    void mydb_destory(MYSQL *mysql)
    {
      if(mysql==NULL)
      {
        fprintf(stderr,"mysql error
    ");
        return 0;
      }
      else
      {
        mysql_close(mysql);
      }
    }

    client.c:

    //gcc client.c -o client `pkg-config --cflags --libs gtk+-2.0` -lpthread
    
    
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    #include "client.h"
    
    void closeApp(GtkWidget *window,gpointer data)
    {
        int sendmsg_len=write(socketcon,"quit",strlen("quit"));
        if(sendmsg_len<=0)
        {
            if(write_to_file("write error")==0)
            {
                exit(-1);
            }
            exit(-1);
        }
        pthread_kill(client_thr,SIGKILL);
        close(socketcon);
        gtk_main_quit();
    }
    
    void Clear_Local_message()
    {
            GtkTextIter start,end;
            gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Send_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/
            gtk_text_buffer_delete(GTK_TEXT_BUFFER(Send_buffer),&start,&end);/*删除缓冲区内容*/
    }
    
    /*----------------------------------------------------------------------------*/
    void Put_Local_message(const gchar *text)
    {
            GtkTextIter start,end;
            gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Rcv_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/
        gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"使用者:
    ",10);/*插入文本到缓冲区*/
            gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,text,strlen(text));/*插入文本到缓冲区*/
            gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"
    ",1);/*插入文本到缓冲区*/
        int sendmsg_len=write(socketcon,text,strlen(text));
        if(sendmsg_len<=0)
        {
            if(write_to_file("write error")==0)
            {
                exit(-1);
            }
            exit(-1);
        }
    }
    
    /*----------------------------------------------------------------------------*/
    void Show_Err(char *err)
    {
        GtkTextIter start,end;
        gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Rcv_buffer),&start,&end);
        gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,err,strlen(err));
    }
    
    /*----------------------------------------------------------------------------*/
    /*发送函数----------------------------------------------------------------------*/
    void on_send(GtkButton *SaveButton, GtkWidget *Send_textview)/*保存按钮的回调函数,每当‘保存’按钮被按下的时候,都会触发这个函数*/
    {
        GtkTextIter start,end;/*定义迭代器起点终点*/
        gchar *S_text,*R_text;/*定义文字存储变量*/
    
        gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Send_buffer),&start,&end);
        S_text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(Send_buffer),&start,&end,FALSE);
    
        R_text = S_text;/*把发送文本交换到接收文本*/
    
        if(strcmp(R_text,"")!=0)
        {
            //Get_Local_message();
            Clear_Local_message();
            Put_Local_message(R_text);   
        }
        else
        {
                Show_Err("消息不能为空...!
    ");
        }
        free(R_text);
        //free(S_text);
    }
    /*----------------------------------------------------------------------------*/
    
    /*关闭函数---------------------------------------------------------------------*/
    void on_close(GtkButton *CloseButton,GtkWidget *Send_textview)
    {
        int sendmsg_len=write(socketcon,"quit",strlen("quit"));
        if(sendmsg_len<=0)
        {
            if(write_to_file("write error")==0)
            {
                exit(-1);
            }
            exit(-1);
        }
        pthread_kill(client_thr,SIGKILL);
        close(socketcon);
        gtk_main_quit();
    }
    /*----------------------------------------------------------------------------*/
    
    
    /*主函数-----------------------------------------------------------------------*/
    int main(int argc, char *argv[])
    {
    /*主函数变量声明区*/
        GtkWidget *window/*定义主窗口*/,
              *Send_scrolled_win/*定义发送滚动窗口*/,
              *Rcv_scrolled_win/*定义接收滚动窗口*/;
        GtkWidget *vbox/*定义垂直盒子*/;
        GtkWidget *Button_Box/*定义按钮盒*/,
              *SendButton/*定义发送按钮*/,
              *CloseButton/*定义关闭按钮*/;
        GtkWidget *hseparator/*定义水平分割线*/;
              //*panel_v/*定义垂直分割面板*/,
              //*panel_h/*定义水平分割面板*/;
    
    
        /*------------------------------连接服务端------------------------*/
    
        if(write_to_file("start socket")==0)
        {
            exit(-1);
        }
    
        socketcon=socket(AF_INET,SOCK_STREAM,0);
        if(socketcon<0)
        {
            if(write_to_file("socket error")==0)
        {
            exit(-1);
        }
            exit(-1);
        }
    
        struct sockaddr_in server_addr;
    
        server_addr.sin_family=AF_INET;
        server_addr.sin_addr.s_addr=inet_addr(ip);
        server_addr.sin_port=htons(port);
    
        /*测试*/
        printf("客户端的套接字:%d
    ",socketcon);
    
    
        int res_con=connect(socketcon,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr));
        if(res_con!=0)
        {
            if(write_to_file("connect error")==0)
        {
            exit(-1);
        }
        exit(-1);
        }
    
        printf("连接成功!");
        if(write_to_file("连接成功")==0)
        {
            exit(-1);
        }
    
        /*---------------------------------------------------------------*/ 
    
        /*--------------------客户端的接受消息的线程函数的执行----------------*/
    
        if(pthread_create(&client_thr,NULL,fun_clientreceive,&socketcon)!=0)
        {
            if(write_to_file("pthread_create error")==0)
                {
                exit(-1);
                }
            exit(-1);
        }
        sleep(1);
        /*---------------------------------------------------------------*/
    
        /*-------------------------这是关于窗口的初始化---------------------*/        
        gtk_init(&argc,&argv);/*GTK初始化*/
    
    
        /*------------------------------绘制主窗口----------------------------*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);/*生成主窗口*/
        g_signal_connect(G_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(closeApp),NULL);
        //g_singal_connect(G_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(closeApp),NULL);
       // g_signal_connect(G_OBJECT(window),"delete_event",G_CALLBACK(gtk_main_quit),NULL);/*连接信号,关闭窗口*/
        gtk_window_set_title(GTK_WINDOW(window),"聊天窗口");/*设置主窗口标题*/
        gtk_container_set_border_width(GTK_CONTAINER(window),10);/*设置主窗口边框*/
        gtk_widget_set_size_request(window,400,300);/*设置主窗口初始化大小*/
        gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);/*设置主窗口初始位置*/
    
        /*------------------------------设置Send_text view-------------------------*/
        Send_textview = gtk_text_view_new();/*生成text view*/
        gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(Send_textview),GTK_WRAP_WORD);/*处理多行显示的模式*/
        gtk_text_view_set_justification(GTK_TEXT_VIEW(Send_textview),GTK_JUSTIFY_LEFT);/*控制文字显示方向的,对齐方式*/
        gtk_text_view_set_editable(GTK_TEXT_VIEW(Send_textview),TRUE);/*允许text view内容修改*/
        gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(Send_textview),TRUE);/*设置光标可见*/
            gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(Send_textview),5);/*设置上行距*/
        gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(Send_textview),5);/*设置下行距*/
        gtk_text_view_set_pixels_inside_wrap(GTK_TEXT_VIEW(Send_textview),5);/*设置词距*/
            gtk_text_view_set_left_margin(GTK_TEXT_VIEW(Send_textview),10);/*设置左边距*/
        gtk_text_view_set_right_margin(GTK_TEXT_VIEW(Send_textview),10);/*设置右边距*/
        Send_buffer =  gtk_text_view_get_buffer(GTK_TEXT_VIEW(Send_textview));/*返回text view被显示的buffer*/
    
    
            /*------------------------------设置Rcv_text view-------------------------*/
        Rcv_textview = gtk_text_view_new();/*生成text view*/
        gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(Rcv_textview),GTK_WRAP_WORD);/*处理多行显示的模式*/
        gtk_text_view_set_justification(GTK_TEXT_VIEW(Rcv_textview),GTK_JUSTIFY_LEFT);/*控制文字显示方向的,对齐方式*/
        gtk_text_view_set_editable(GTK_TEXT_VIEW(Rcv_textview),TRUE);/*允许text view内容修改*/
        gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(Rcv_textview),TRUE);/*设置光标可见*/
            gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(Rcv_textview),5);/*设置上行距*/
        gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(Rcv_textview),5);/*设置下行距*/
        gtk_text_view_set_pixels_inside_wrap(GTK_TEXT_VIEW(Rcv_textview),5);/*设置词距*/
            gtk_text_view_set_left_margin(GTK_TEXT_VIEW(Rcv_textview),10);/*设置左边距*/
        gtk_text_view_set_right_margin(GTK_TEXT_VIEW(Rcv_textview),10);/*设置右边距*/
        gtk_text_view_set_editable(GTK_TEXT_VIEW(Rcv_textview),FALSE);/*设置接收文字区不可被编辑*/
        Rcv_buffer =  gtk_text_view_get_buffer(GTK_TEXT_VIEW(Rcv_textview));/*返回text view被显示的buffer*/   
    
    
        /*------------------------------设置发送窗口滚动条-------------------------------*/
        Send_scrolled_win = gtk_scrolled_window_new(NULL,NULL);/*生成滚动条的窗口*/
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(Send_scrolled_win),Send_textview);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Send_scrolled_win),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);/*滚动条属性*/
    
    
        /*------------------------------设置接收窗口滚动条-------------------------------*/
        Rcv_scrolled_win = gtk_scrolled_window_new(NULL,NULL);/*生成滚动条的窗口*/
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(Rcv_scrolled_win),Rcv_textview);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Rcv_scrolled_win),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);/*滚动条属性*/
    
        /*------------------------------设置垂直盒子------------------------------*/
        vbox = gtk_vbox_new(FALSE,0);/*生成一个垂直排布的盒子*/
    
    
        /*------------------------------设置发送按钮------------------------------*/
        SendButton = gtk_button_new_with_label("发送");/*生成发送按钮*/
        g_signal_connect(G_OBJECT(SendButton),"clicked",G_CALLBACK(on_send),(gpointer)Send_textview);/*给按钮加上回调函数*/
    
        /*------------------------------设置关闭按钮------------------------------*/
        CloseButton = gtk_button_new_with_label("关闭");/*生成关闭按钮*/
        g_signal_connect(G_OBJECT(CloseButton),"clicked",G_CALLBACK(on_close),(gpointer)Send_textview);
    
        /*------------------------------设置按钮盒子------------------------------*/    
        Button_Box = gtk_hbutton_box_new();/*生成按钮盒*/
        gtk_box_set_spacing(GTK_BOX(Button_Box),1);/*按钮之间的间隔*/
        gtk_button_box_set_layout(GTK_BUTTON_BOX(Button_Box),GTK_BUTTONBOX_END);/*按钮盒内部布局,风格是尾对齐*/
        gtk_container_set_border_width(GTK_CONTAINER(Button_Box),5);/*边框宽*/
    
        /*------------------------------设置分割线--------------------------------*/
        hseparator = gtk_hseparator_new();
    
        /*------------------------------添加到容器--------------------------------*/
        gtk_container_add(GTK_CONTAINER(vbox),Rcv_scrolled_win);/*包装滚动条窗口到主窗口*/
        gtk_container_add(GTK_CONTAINER(vbox),hseparator);/*加入一条分割线*/
        gtk_container_add(GTK_CONTAINER(vbox),Send_scrolled_win);/*包装滚动条窗口到主窗口*/   
        gtk_container_add(GTK_CONTAINER(vbox),Button_Box);/*把按钮盒包装到vbox中*/
        gtk_box_pack_start(GTK_BOX(Button_Box),CloseButton,TRUE,TRUE,5);/*把关闭按钮包装到按钮盒里面去*/
        gtk_box_pack_start(GTK_BOX(Button_Box),SendButton,TRUE,TRUE,5);/*把发送按钮包装到按钮盒里面去*/
        gtk_container_add(GTK_CONTAINER(window),vbox);/*将盒子封装到主窗口中去*/   
    
        /*------------------------------显示所有东西------------------------------*/
        gtk_widget_show_all(window);/*显示所有东西*/
    
        gtk_main();/*主循环*/
    
        /*-----------------------------等待线程退出-------------------------------*/
        char *client_message;
        int res=1;
    
        if(pthread_join(client_thr,(void *)&client_message)==0)
        {
            printf("%s
    ",client_message);
        }
        else
        {
            if(write_to_file("pthread_join error")==0)
            {
                exit(-1);
            }
            exit(-1);
        }
    
        /*----------------------------------------------------------------------*/
        pthread_kill(client_thr,SIGKILL);
        return 0;/*退出程序*/
        }

    client.h:

    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <pthread.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/signal.h>
    #include <gtk/gtk.h>
    
    #define MAXLEN 1024
    
    typedef struct mysocketinfo{
        int socketcon;
        unsigned long ipaddr;
        unsigned short port;
    }_mysocketinfo;
    
    const char *ip="127.0.0.1";
    const int port=8888;
    
    int socketcon;
    
    /*---------------------------------客户端接受线程---------------------------------*/
    pthread_t client_thr;
    /*------------------------------------------------------------------------------*/
    
    /*全局变量声明区-----------------------------------------------------------------*/
        GtkWidget *Send_textview/*定义发送文本区*/,
                *Rcv_textview/*定义接收文本区*/;
        GtkTextBuffer *Send_buffer/*定义发送文本缓冲区*/,
                    *Rcv_buffer/*定义接收文本缓冲区*/;
    
    /*----------------------------------------------------------------------------*/
    
    int write_to_file(char *name)
    {   
        FILE *fp;
        char buffer[50];
        time_t timep;
        char time_buffer[100];
    
        fp=fopen("client.log","a+");
        if(fp==NULL)
        {
            exit(-1);
        }   
    
        sprintf(buffer,"%s
    ",name);
        if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
        {
            return 0;
        }
    
        time (&timep);
        sprintf(time_buffer,"%s
    ",ctime(&timep));
        if(fwrite(time_buffer,sizeof(char),strlen(time_buffer),fp)<=0)
        {
            return 0;
        }       
    
        fclose(fp);
        return 1;
    }
    
    void *fun_clientreceive(void *_socketcon)
    {
        char buffer[MAXLEN];
        int socketcon=*((int *)_socketcon);
    
        while(1)
        {
            memset(buffer,'',sizeof(buffer));
            int buffer_length=read(socketcon,buffer,MAXLEN-1);
            if(buffer_length<=0)
            {
                if(write_to_file("client read error")==0)
                    {
                    exit(-1);
                    }
                exit(-1);
            }
            else
            {
                GtkTextIter start,end;/*定义迭代器起点终点*/
                    gchar *S_text,*R_text;/*定义文字存储变量*/
    
                    gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Rcv_buffer),&start,&end);
    
                gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"服务器:
    ",10);/*插入文本到缓冲区*/
                    gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,buffer,strlen(buffer));/*插入文本到缓冲区*/
                    gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"
    ",1);/*插入文本到缓冲区*/
            }
        }
        pthread_exit("线程退出!");
    }

    server.c:

    #include "server.h"
    
    int checkthriskill(pthread_t thr)
    {
           //1存在,0不存在
            int res=1;
            //判断线程是否存在
            int kill_rc=pthread_kill(thr,0);
    
        if(kill_rc == ESRCH)
        {
            printf("ID为%d的线程不存在或者已经退出。
    ",(unsigned int)thr);
            res=0;
        }
        else if(kill_rc == EINVAL)
        {
            printf("发送信号非法。
    ");
            res=0;
        }
        else
        {
          printf("ID为%d的线程目前仍然存活。
    ",(unsigned int)thr);
          res=1;
        }
        return res;
    }
    
    
    
    //删除杀死的线程
    int delete_client(void *fp,int num)
    {
        int i=0;
    
        pthread_t *ps=(pthread_t *)fp;
    
        if(num<1)
        {
            return 0;   
        }
    
        for(i=num;i<=arr;i++)
        {
            ps[i]=ps[i+1];  
        arrconsocket[i]=arrconsocket[i+1];
        }
    
        return 1;
    }
    
    
    
    
    
    int main()
    {
        int service_socket=socket(AF_INET,SOCK_STREAM,0);//创建服务端的套接字
        if(service_socket<0)//如果创建套接字失败了
        {
            if(write_to_file("server socket error")==0)
        {
            exit(-1);
        }
            exit(-1);
        }
    
        struct sockaddr_in addr;//套接字地址结构
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);
        addr.sin_addr.s_addr=inet_addr(ip);
    
        if(bind(service_socket,(struct sockaddr*)&addr,sizeof(addr))<0)//连接套接字结构和套接字
        {
            if(write_to_file("bind error")==0)
        {
            exit(-1);
        }
            exit(-1);
        }
    
        int listen_socket=listen(service_socket,10);//监听套接字
        if(listen_socket<0)//失败的处理
        {
            if(write_to_file("listen error")==0)
        {
            exit(-1);
        }
            exit(-1);
        }
    
        pthread_t thraccept;//创建的线程数组
        //pthread_create创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后,就开始运行相关的线程函数
        if(pthread_create(&thraccept,NULL,fun_thraccepthander,&service_socket)!=0)
        {
        if(write_to_file("pthread_create error")==0)
        {
            exit(-1);
        }
            exit(-1);
        }
        sleep(1);
    
        while(1)
        {
            int i=1;
            for(i=1;i<=arr;i++)
            {
                if(checkthriskill(arrthrreceiveclient[i])==0)
                {
                    printf("have a thread is killed
    ");
                    if(delete_client((void*)(&arrthrreceiveclient),i)==0)
                    {
                if(write_to_file("delete_client error")==0)
                {
                    exit(-1);
                }
                            exit(-1);
                    }
                    --arr;
                }
            }
            printf("在线人数:%d
    ",arr);
            if(arr<=0)
            {
                printf("没有客户端连接
    ");
            }
            else
            {
                int i=0;
                char buf[MAXLEN];
                ssize_t size=0;
    
                memset(buf,'',MAXLEN);
                size=read(STDIN_FILENO,buf,sizeof(buf));
                if(size>0)
                {
                    buf[size]='';
                }
                else
                {
            if(write_to_file("read error")==0)
            {
                exit(-1);
            }
                    break;
                }
    
                for(i=1;i<=arr;i++)
                {
                    int sendmsg_len=write(arrconsocket[i].socketcon,buf,size);
                    if(sendmsg_len>0)
                    {
                        printf("向客户端%s:%d发送成功
    ",arrconsocket[i].ipaddr,arrconsocket[i].port);
                    }
                    else
                    {
                        printf("向客户端%s:%d发送失败
    ",arrconsocket[i].ipaddr,arrconsocket[i].port);
                    }
                }
            }
            sleep(1);
        }
        if(arr>=1)
        {
            char *message;
            int res=1;
            printf("等待线程退出
    ");
    
    
    
                if((res=pthread_join(thraccept,(void*)&message))==0)
                {
                    printf("%s
    ",message);
                }
                else
                {
            if(write_to_file("pthread_join error")==0)
            {
                exit(-1);
            }
            exit(-1);
                }
    
        }
        else
        {
            printf("没有线程
    ");
        }
        close(service_socket);
        pthread_kill(thraccept,SIGKILL);
        return(0);
    }

    server.h:

    #include <unistd.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <pthread.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <errno.h>
    #include <time.h>
    
    #define MAXLEN 1024
    #define MAXTHR 10
    
    const int port=8888;
    const char *ip="127.0.0.1";
    
    typedef struct mysocketinfo{
        int socketcon;
        char *ipaddr;
        uint16_t port;
    }_mysocketinfo;
    
    pthread_t arrthrreceiveclient[10];
    struct mysocketinfo arrconsocket[10];
    static int arr=0;
    
    int exit_thr(void *_socketcon)
    {
        int socketcon=*((int *)_socketcon);
        int i=0,k=0;
        printf("线程退出
    ");
        for(i=0;i<=arr;i++){
            if(arrconsocket[i].socketcon==socketcon)
            {
                    for(k=i;k<=arr;k++)
                    {
                        arrconsocket[k]=arrconsocket[k+1];
                            arrthrreceiveclient[k]=arrthrreceiveclient[k+1];
                     }
            }
        }
    }
    
    /*写入日志文件*/
    int write_to_file(char *name)
    {   
        FILE *fp;
        char buffer[50];
        time_t timep;
        char time_buffer[100];
    
        fp=fopen("server.log","a+");
        if(fp==NULL)
        {
            exit(-1);
        }       
    
        sprintf(buffer,"%s
    ",name);
        if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
        {
            return 0;
        }
    
        time (&timep);
        sprintf(time_buffer,"%s
    ",ctime(&timep));
        if(fwrite(time_buffer,sizeof(char),strlen(time_buffer),fp)<=0)
        {
            return 0;
        }
    
        fclose(fp);
        return 1;
    }
    
    //接收消息函数
    void *fun_thrreceivehandler(void *socketcon){
        char buffer[MAXLEN];
        int buffer_length;
        int socketcon1;
    
    
        socketcon1=*((int*)socketcon);
        while(1){
            memset(buffer,'',sizeof(buffer));//或者使用函数bzero(buffer,20);
    
            printf("接收套接字:%d
    ",socketcon1);
            buffer_length=read(socketcon1,buffer,MAXLEN-1);
            if(buffer_length<0)
            {
                    if(write_to_file("read from client error")==0)
            {
                exit(-1);
            }
            exit(-1);
            }/*客户端的退出没有捕获到,此DUG待处理*/
            else if(strncmp(buffer,"NULL",4)==0)
            {
            fprintf(stdout,"套接字:%d close
    ",socketcon1);
            exit_thr(&socketcon1);
            arr--;
                pthread_exit("线程退出!");   
            break;
            }
            if(strncmp(buffer,"quit",4)==0)
            {
                fprintf(stdout,"套接字:%d close
    ",socketcon1);
                exit_thr(&socketcon1);
            arr--;
                pthread_exit("线程退出!");
            break;
    
            }
            //printf("buffer:%s
    ",buffer);
            buffer[buffer_length]='';
            printf("客户端%d:%s
    ",socketcon1,buffer);
    
        /*------------------------这是通过服务端向每个客户端写入数据-------------------*/
        int i=0;
    
    
        for(i=1;i<=arr;i++)
            {
            if(arrconsocket[i].socketcon!=socketcon1)
            {
        /*------------------------这是传递客户端的名字-------------------------------*/
                char client_name[50];
                sprintf(client_name,"中转%s--%d--->%s",arrconsocket[i].ipaddr,arrconsocket[i].port,buffer);
    
        /*------------------------------------------------------------------------*/
    
                int sendmsg_len=write(arrconsocket[i].socketcon,client_name,sizeof(client_name));
                    if(sendmsg_len>0)
                    {
                        printf("向客户端%s:%d发送成功
    ",arrconsocket[i].ipaddr,arrconsocket[i].port);
                    }
                    else
                    {
                        printf("向客户端%s:%d发送失败
    ",arrconsocket[i].ipaddr,arrconsocket[i].port);
                    }
            }
            }   
    
        /*------------------------------------------------------------------------*/
            sleep(1);
        }
         printf("接受数据线程结束
    ");
    }
    
    
    //处理acceot
    void *fun_thraccepthander(void *socketlisten){
        char buf[MAXLEN];
        ssize_t size;
        int sockaddr_in_size=sizeof(struct sockaddr_in);//sockaddr_in结构体的大小
        int socklisten1=*((int*)socketlisten);
        int socketcon;
        pthread_t thrreceive=0;
        struct sockaddr_in client_addr;
        char accept_message[50];
    
        while(1){
        socketcon=accept(socklisten1,(struct sockaddr*)(&client_addr),(socklen_t *)(&sockaddr_in_size));
        if(socketcon<0)
        {
        if(write_to_file("accept error")==0)
        {
            exit(-1);
        }
        }   
        else{
        if(write_to_file("accept success")==0)
        {
            exit(-1);
        }
    
        sprintf(accept_message,"ip: %s,port: %d",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
            if(write_to_file(accept_message)==0)
        {
            exit(-1);
        }
        }
    
    
        printf("在线人数:%d
    ",++arr);
        printf("连接客户端的套接字:%d
    ",socketcon);
    
        arrconsocket[arr].socketcon=socketcon;
        arrconsocket[arr].ipaddr=inet_ntoa(client_addr.sin_addr);
        arrconsocket[arr].port=client_addr.sin_port;
    
        //接收的消息 
        if(pthread_create(&thrreceive,NULL,fun_thrreceivehandler,&socketcon)!=0)
        {
        if(write_to_file("pthread_create error")==0)
        {
            exit(-1);
        }
            break;
        }
        arrthrreceiveclient[arr]=thrreceive;
        sleep(1);
        }
    
        char *message;
            int res=1;
            printf("等待接受的子线程退出
    ");
    
    
    
            if((res=pthread_join(thrreceive,(void*)&message))==0)
            {
                 printf("%s
    ",message);
            }
            else
            {
            if(write_to_file("pthread_join error")==0)
            {
                exit(-1);
            }
                    exit(-1);
            }
    
    }

    Makefile文件:

    all:  app client server
    
    # If using Redhat 8+ or Fedora, may need to add -L/usr/lib/mysql to link to MySQL. 
    #gcc -o app -I/usr/include/mysql main.c -L/usr/lib64/mysql -lmysqlclient `pkg-config --cflags --libs gtk+-2.0`
    app: main.c view.h mydb.h
    
        #gcc main.c -o app `pkg-config --cflags --libs gtk+-2.0` 
        gcc -o app -I/usr/include/mysql main.c -L/usr/lib64/mysql -lmysqlclient `pkg-config --cflags --libs gtk+-2.0`
    
    client: client.c client.h
        gcc client.c -o client `pkg-config --cflags --libs gtk+-2.0` -lpthread
    
    server: server.c server.h
        gcc server.c -o server -lpthread
    
    clean:
        rm -f app
        rm -f client
        rm -f server

    附上效果图:

    这里写图片描述

    这里写图片描述

    这里写图片描述

    技术不分国界
  • 相关阅读:
    python中创建列表、元组、字符串、字典、集合
    python中字典的键不允许重复
    python中生成字典
    python中实现列表元素的倒序排列
    python中实现字典的逆向排列
    python中增加字典的键值对(项)、修改键值对的值
    python中访问字典
    Fortran 2003:完美还是虚幻?(节选)
    感谢裘宗燕老师!
    “符号化”的效用和缺失
  • 原文地址:https://www.cnblogs.com/angels-yaoyao/p/12443601.html
Copyright © 2020-2023  润新知