• linux 实现仿QQ应用程序


    我个人相信很多人都想自己实现一个linux版本的应用程序,我也是其中的一员,开始写程序的时候,四处碰壁,上网也搜索了很多资料,要么不完整,要么系统信息过大,具体研究起来消耗时间过多,所以决定自己写一个基于linux,GTK的仿QQ应用程序,发现GTK编写应用程序,确实没有java等高级语言编写更方便,很多处理我暂时也没有实现,这是我的第一个QQ版本,我也希望志同道合的人能给我更多的建议修改>

    这是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)
            {
              printf("success!
    ");
              //登陆到客户端窗口程序
              execv("./log_client", NULL);
            }
            else
            {
              printf("failed
    ");
            }
                printf("用户名是:%s",username);  
                printf("
    ");  
                printf("密码是:%s
    ",password);  
            } 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:
    create database qq;

     /*
     * 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;
    
    void closeApp(GtkWidget *window,gpointer data)
    {
      mydb_destory(mysql);
      gtk_main_quit();
    }
    
    void button_clicked_ok(GtkWidget *button,gpointer username_data)
    {
      const char *username_text=gtk_entry_get_text(GTK_ENTRY((GtkWidget*)username_data));
      const char *password_text=gtk_entry_get_text(GTK_ENTRY((GtkWidget*)password_entry));
      int res=0;
    
      mydb_init();
      if(mydb_test(mysql,username_text,password_text)==1)
      {
        printf("success!
    ");    
      }
      else
      {
        printf("failed
    ");
      }
    
    }
    
    void button_clicked_cancel(GtkWidget *button,gpointer data)
    {
      gtk_main_quit();
    }
    
    void add_widget_with_label(GtkContainer *vbox,gchar *caption,GtkWidget *widget)
    {
      GtkWidget *label=gtk_label_new(caption);
      GtkWidget *hbox=gtk_hbox_new(TRUE,0);
    
      gtk_container_add(GTK_CONTAINER(hbox),label);
      gtk_container_add(GTK_CONTAINER(hbox),widget);
    
      gtk_box_pack_start(GTK_BOX(hbox),label,TRUE,TRUE,3);
      gtk_box_pack_start(GTK_BOX(hbox),widget,TRUE,TRUE,3);
    
      gtk_container_add(GTK_CONTAINER(vbox),hbox);
    }

    实现mydb.h:
    这里你得自己创建数据库
    创建表对象:children
    表数据:name,password
    mysql_real_connect连接自己创建的数据库:账号(我的:zhangsan)密码:123456

    #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","zhangsan","123456","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.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>
    
    #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;
    pthread_t thrreceive;
    int socketcon;

    和窗口函数log_client.c:

    //gcc log_client.c -o log_client `pkg-config --cflags --libs gtk+-2.0`    
    //gtk_widget_set_size_request (window,450, 420);
    #include <gtk/gtk.h>
    #include "client.h"
    
    /*全局变量声明区-----------------------------------------------------------------*/
        GtkWidget *window/*定义主窗口*/,
              *Send_scrolled_win/*定义发送滚动窗口*/,
              *Rcv_scrolled_win/*定义接收滚动窗口*/,
              *Send_textview/*定义发送文本区*/,
              *Rcv_textview/*定义接收文本区*/;
        GtkTextBuffer *Send_buffer/*定义发送文本缓冲区*/,*Rcv_buffer/*定义接收文本缓冲区*/;
        GtkWidget *vbox/*定义垂直盒子*/;
        GtkWidget *SaveButton/*定义保存按钮*/;
    /*----------------------------------------------------------------------------*/
    
    /*客户端核心*/
    void *fun_thrreceive(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)
            {
                printf("空数据
    ");
                exit(0);
            }
            GtkTextBuffer *R_buffer/*定义接收文本缓冲区*/;
                GtkTextIter start,end;/*定义迭代器起点终点*/
                gchar *R_text;/*定义文字存储变量*/
    
                R_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Rcv_textview));/*获取接收文本缓冲区*/
                R_text = buffer;/*把发送文本交换到接收文本*/
                //gtk_text_view_append_with_tag(GTK_TEXT_VIEW(R_buffer),R_text,-1);
                gtk_text_buffer_set_text(R_buffer,R_text,-1);/*在接收文本区显示发送的内容*/
            //printf("")
        }
    }
    
    
    void client(gchar *S_text)
    {
        printf("start socket
    ");
        socketcon=socket(AF_INET,SOCK_STREAM,0);
        if(socketcon<0)
        {
            perror("socket error
    ");
            exit(0);
        }
    
        struct sockaddr_in client_addr;
        client_addr.sin_family=AF_INET;
        client_addr.sin_addr.s_addr=inet_addr(ip);
        client_addr.sin_port=htons(port);
    
        printf("客户端的套接字:%d
    ",socketcon);
    
        int res_con=connect(socketcon,(struct sockaddr*)(&client_addr),sizeof(struct sockaddr));
        if(res_con!=0){
            perror("connect error
    ");
            exit(0);
        }
    
        printf("连接成功!
    ");
        /*if(pthread_create(&thrreceive,NULL,fun_thrreceive,&socketcon)!=0)
        {
            perror("pthread_create error
    ");
            exit(0);
        }
        sleep(1);*/
    
        //while(1){
            char *buf;
            int size=0;
    
            //memset(buf,'',sizeof(buf));
    
            buf=S_text;
            size=strlen(buf);
    
            if(size>0)
            {
                buf[size]='';
            }
            else if(size==0)
            {
                printf("不能为空
    ");
                int sendmsg_len=write(socketcon,"NULL",4);
                if(sendmsg_len==4)
                {
                    printf("发送退出码成功!
    ");
                }
                else{
                    printf("发送失败!
    ");
                }
                //break;
            }
            else{
                perror("read error
    ");
                //break;
            }
    
            int sendmsg_len=write(socketcon,buf,size);
            if(sendmsg_len>0)
            {
                printf("发送成功,客户端套接字:%d
    ",socketcon);
            }
            else
            {
                printf("发送失败!
    ");
            }
            printf("%s
    ",buf);
            if(strcmp(buf,"quit
    ")==0)
            {
                close(socketcon);
                pthread_kill(thrreceive,SIGKILL);
                exit(0);
            }
            sleep(2);
        //}
        int len=write(socketcon,"NULL",4);
        if(len==4)
        {
            printf("发送成功,客户端套接字:%d
    ",socketcon);
        }
        else
        {
            printf("发送失败!
    ");
        }
        close(socketcon);
        //pthread_kill(thrreceive,SIGKILL);
    }
    
    void closeApp(GtkWidget *window,gpointer data)
    {
        close(socketcon);
        pthread_kill(thrreceive,SIGKILL);
        gtk_main_quit();
    }
    
    /*发送函数----------------------------------------------------------------------*/
    void on_send(GtkButton *SaveButton, GtkWidget *Send_textview)/*保存按钮的回调函数,每当‘保存’按钮被按下的时候,都会触发这个函数*/
    {
        GtkTextBuffer *S_buffer/*定义发送文本区缓冲区*/,*R_buffer/*定义接收文本缓冲区*/;
        GtkTextIter start,end;/*定义迭代器起点终点*/
        gchar *S_text,*R_text;/*定义文字存储变量*/
    
        S_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Send_textview));/*获取文本区*/
        gtk_text_buffer_get_start_iter(Send_buffer,&start);/*得到当前文本区域的起始位置*/
        gtk_text_buffer_get_end_iter(Send_buffer,&end);/*得到当前文本区域的结束位置*/
        S_text = gtk_text_buffer_get_text(Send_buffer,&start,&end,TRUE/*FALSE*/);/*返回start end之间的所有文本,最后一个参数是TRUE的话那么可见的文本都将被返回*/
    
        //g_print("%s/n",S_text);/*2种方式都可以输出文本区域的内容*/
        //g_print(S_text);
        //gtk_text_view_append_with_tag( GtkTextView* text_view, const gchar* text, GtkTextTag* text_tag)
        R_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Rcv_textview));/*获取接收文本缓冲区*/
        R_text = S_text;/*把发送文本交换到接收文本*/
        //gtk_text_view_append_with_tag(GTK_TEXT_VIEW(R_buffer),R_text,-1);
        gtk_text_buffer_set_text(R_buffer,R_text,-1);/*在接收文本区显示发送的内容*/
        //gtk_text_buffer_set_text(S_buffer,"",-1);
       /* pthread_t thr_client;
        if(pthread_create(&thr_client,NULL,client,S_text)!=0)
        {
        exit(0) 
        }
       */
        client(S_text);
        /*
        这是客户端的操作
        client(S_text);
        */
    }
    /*----------------------------------------------------------------------------*/
    
    /*主函数-----------------------------------------------------------------------*/
    int main(int argc, char *argv[])
    {
    
        gtk_init(&argc,&argv);/*GTK初始化*/
    /*函数实现区*/
    
        /*------------------------------绘制主窗口----------------------------*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);/*生成主窗口*/
       // g_signal_connect(G_OBJECT(window),"delete_event",G_CALLBACK(gtk_main_quit),NULL);/*连接信号,关闭窗口*/
        g_signal_connect(G_OBJECT(window),"delete_event",GTK_SIGNAL_FUNC(closeApp),NULL);
        gtk_window_set_title(GTK_WINDOW(window),"Save Text");/*设置主窗口标题*/
        gtk_container_set_border_width(GTK_CONTAINER(window),10);/*设置主窗口边框*/
        gtk_widget_set_size_request(window,400,420);/*设置主窗口初始化大小*/
        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),FALSE);/*允许text view内容修改*/
        gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(Rcv_textview),FALSE);/*设置光标可见*/
            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);/*设置右边距*/
        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_set_policy(GTK_SCROLLED_WINDOW(Send_scrolled_win),GTK_POLICY_AUTOMATIC,GTK_POLICY_ALWAYS);/*滚动条属性*/
        /*------------------------------设置接收窗口滚动条-------------------------------*/
        Rcv_scrolled_win = gtk_scrolled_window_new(NULL,NULL);/*生成滚动条的窗口*/
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Rcv_scrolled_win),GTK_POLICY_AUTOMATIC,GTK_POLICY_ALWAYS);/*滚动条属性*/
        /*------------------------------设置垂直盒子------------------------------*/
        vbox = gtk_vbox_new(FALSE,10);/*生成一个垂直排布的盒子*/
        /*------------------------------设置发送按钮------------------------------*/
        SaveButton = gtk_button_new_with_label("发送");/*生成一个按钮*/
        gtk_widget_set_size_request (SaveButton,400, 5);
        g_signal_connect(G_OBJECT(SaveButton),"clicked",G_CALLBACK(on_send),(gpointer)Send_textview);/*给按钮加上回调函数*/
        /*------------------------------包装所有容器------------------------------*/
        gtk_container_add(GTK_CONTAINER(Send_scrolled_win),Send_textview);/*包装textview到滚动条窗口*/
        gtk_container_add(GTK_CONTAINER(Rcv_scrolled_win),Rcv_textview);/*包装textview到滚动条窗口*/
        gtk_container_add(GTK_CONTAINER(vbox),Rcv_scrolled_win);/*包装滚动条窗口到主窗口*/
        gtk_container_add(GTK_CONTAINER(vbox),Send_scrolled_win);/*包装滚动条窗口到主窗口*/
        gtk_box_pack_start(GTK_BOX(vbox),SaveButton,TRUE,TRUE,5);/*把按钮包装到vbox里面去*/
        gtk_container_add(GTK_CONTAINER(window),vbox);/*将盒子封装到主窗口中去*/   
        /*------------------------------显示所有东西------------------------------*/
        gtk_widget_show_all(window);/*显示所有东西*/
    
        gtk_main();/*主循环*/
        return 0;/*退出程序*/
        }

    最后是服务端的代码server.c:

    #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>
    
    #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 checkthriskill(pthread_t thr)
    {
           //1存在,0不存在
            int res=1;
            //判断线程是否存在
            int kill_rc=pthread_kill(thr,0);
    
        if(kill_rc == ESRCH)
        {
            printf("ID为0x%x的线程不存在或者已经退出。
    ",(unsigned int)thr);
            res=0;
        }
        else if(kill_rc == EINVAL)
        {
            printf("发送信号非法。
    ");
            res=0;
        }
        else
        {
          printf("ID为0x%x的线程目前仍然存活。
    ",(unsigned int)thr);
          res=1;
        }
        return res;
    }
    
    //接收消息函数
    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)
            {
                printf("接收客户端失败了
    ");
            }
            else if(strncmp(buffer,"NULL",4)==0)
            {
            int i=0,k=0;
            printf("线程退出
    ");
             for(i=0;i<=arr;i++)
                {
                    if(arrconsocket[i].socketcon==socketcon1)
                    {
                        for(k=i;k<=arr;k++)
                        {
                            arrconsocket[k]=arrconsocket[k+1];
                            arrthrreceiveclient[k]=arrthrreceiveclient[k+1];
                        }
                    }
                }
            arr--;
                pthread_exit("线程退出");   
            break;
            }
            if(strcmp(buffer,"quit
    ")==0)
            {
                int i=0;
                int k=0;
    
                fprintf(stdout,"套接字:%d close
    ",socketcon1);
                for(i=0;i<=arr;i++)
                {
                    if(arrconsocket[i].socketcon==socketcon1)
                    {
                        for(k=i;k<=arr;k++)
                        {
                            arrconsocket[k]=arrconsocket[k+1];
                            arrthrreceiveclient[k]=arrthrreceiveclient[k+1];
                        }
                    }
                }
        arr--;
        break;
    
            }
            printf("buffer:%s
    ",buffer);
            buffer[buffer_length]='';
            printf("客户端%d:%s
    ",socketcon1,buffer);
            sleep(1);
        }
         printf("接受数据线程结束
    ");
    }
    
    //删除杀死的线程
    int delete_client(void *fp,int num)
    {
        /*
        int pthreadnum=0;
        int thrreceiveclientcount=0;//接收消息的线程ID
        int conclientcount=0;//在线人数
        */
    
        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;
    }
    
    //处理acceot
    void *fun_thraccepthander(void *socketlisten){
        char buf[MAXLEN];
        ssize_t size;
        int sockaddr_in_size=sizeof(struct sockaddr_in);//sockaddr_in结构体的大小
        struct sockaddr_in client_addr;
        int socklisten1=*((int*)socketlisten);
        int socketcon;
        pthread_t thrreceive=0;
    
        while(1){
        socketcon=accept(socklisten1,(struct sockaddr*)(&client_addr),(socklen_t *)(&sockaddr_in_size));
        if(socketcon<0)
        {
            perror("accept error
    ");
            exit(5);
        }   
        else{
            printf("accept success
    ");
                printf("ip:%s,port:%d
    ",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
        }
    
    
        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)
        {
            perror("pthread_create error
    ");
            exit(6);
        }
        arrthrreceiveclient[arr]=thrreceive;
        sleep(1);
        }
        char *message;
            int res=1;
            printf("等待接受的子线程退出
    ");
    
    
    
            if((res=pthread_join(thrreceive,(void*)&message))==0)
            {
                 printf("%s
    ",message);
            }
            else
            {
                 printf("pthread_join error:%d
    ",res);
            }
    }
    
    /*
    void *fun_thrfile(void *socketcon)
    {
        int _socketcon=*((int *)socketcon);
        int sockfd,addrlen,n;
        struct sockaddr_in addr;
        char buf[MAXLEN];
        int sock_tmp;
        int count=0;
        int k=0;
        int m=0;
    
        sockfd=socket(AF_INET,SOCK_DGRAM,0);//服务端的数据报
        if(sockfd<0)
        {
            fprintf(stderr, "socket failed
    ");  
                exit(EXIT_FAILURE);
        }   
    
        addrlen=sizeof(struct sockaddr_in);
        bzero(&addr,addrlen);
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=htonl(INADDR_ANY);
        addr.sin_port=htons(9999);
    
        if(bind(sockfd,(struct sockaddr*)(&addr),sizeof(addr))<0)
        {
            fprintf(stderr, "socket failed
    ");  
                exit(EXIT_FAILURE);
        }
        puts("bind success");
    
        bzero(buf,MAXLEN);
        while(1)
        {
            n=recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)(&addr),&addrlen);
            if(n>0)
            {
                sock_tmp=atoi(buf);
                fprintf(stdout,"sock_tmp:%d",sock_tmp);
            }
            else
            {
                count++;
            }
            if(count==3)
            {
                for(k=0;k<=arr;k++)
                {
                    if(arrconsocket[k].socketcon==sock_tmp)
                    {
                        for(m=k;m<=arr;m++)
                        {
                            arrconsocket[k]=arrconsocket[k+1];
                            arrthrreceiveclient[k]=arrthrreceiveclient[k+1];
                        }
                        arr-=1;
                        break;
                    }
                }
            }           
            sleep(3);
        }
    }
    */
    
    int main()
    {
        int service_socket=socket(AF_INET,SOCK_STREAM,0);//创建服务端的套接字
        if(service_socket<0)//如果创建套接字失败了
        {
            perror("service create error
    ");
            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)//连接套接字结构和套接字
        {
            perror("bind error
    ");
            exit(2);
        }
    
        int listen_socket=listen(service_socket,10);//监听套接字
        if(listen_socket<0)//失败的处理
        {
            perror("listen error
    ");
            exit(3);
        }
    
        pthread_t thraccept;//创建的线程数组
        //pthread_create创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后,就开始运行相关的线程函数
        if(pthread_create(&thraccept,NULL,fun_thraccepthander,&service_socket)!=0)
        {
            perror("pthread_create error
    ");
            exit(4);
        }
        sleep(1);
    /*
        pthread_t thrfile;
        if(pthread_create(&thrfile,NULL,fun_thrfile,&service_socket)!=0)
        {
            perror("pthread_create error
    ");
            exit(4);
        }
        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)
                    {
                        printf("delete_client error
    ");
                        exit(6);
                    }
                    --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
                {
                    perror("read error
    ");
                    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);
                    }
                }
            }
            //pthread_join(id1,&a1);
            sleep(1);
        }
        if(arr>=1)
        {
            char *message;
            int res=1;
            printf("等待线程退出
    ");
    
    
    
                if((res=pthread_join(thraccept,(void*)&message))==0)
                {
                    printf("%s
    ",message);
                }
                else
                {
                    printf("pthread_join error:%d
    ",res);
                }
    
        }
        else
        {
            printf("没有线程
    ");
        }
        close(service_socket);
        pthread_kill(thraccept,SIGKILL);
        return(0);
    }
    ``
    
    最后写上Makefile文件:
    

    all: app

    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

    clean:
    rm -f app
    “`

    但是其中的log_client.c和server.c必须自己手动编写,我没有写入到Makefile文件中

    附上效果图:
    服务端效果,没有用GTK实现界面
    这里写图片描述

    客户端的登录界面:
    这里写图片描述

    客户端的交互界面:这里写图片描述

    注释:本人使用的系统是CentOs7.0,mysql使用的系统默认版本

    技术不分国界
  • 相关阅读:
    《ECMAScript6入门》___阮一峰 笔记
    JS的常用正则表达式 验证密码(转载自用)
    微信小程序 写一个获取验证码 及setInterval 使用基本方法
    python中将图片从客户端(client)推到(POST)到服务器端(server)的方法
    用python将MSCOCO和Caltech行人检测数据集转化成VOC格式
    Tensorflow物体检测(Object Detection)API的使用
    opencv获取IP摄像头(IP-camera)实时视频流
    利用flask将opencv实时视频流输出到浏览器
    Tensorflow同时加载使用多个模型
    opencv在同一窗口打印多张图片
  • 原文地址:https://www.cnblogs.com/angels-yaoyao/p/12443602.html
Copyright © 2020-2023  润新知