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使用的系统默认版本

技术不分国界
原文地址:https://www.cnblogs.com/angels-yaoyao/p/12443602.html