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\n",name);
    if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
    {
        return 0;
    }

    time (&timep);
    sprintf(time_buffer,"%s\n",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\n");
    return;
  }

  ret=mysql_options(mysql,MYSQL_OPT_CONNECT_TIMEOUT,(const char *)&timeout);
  if(ret!=0)
  {
    fprintf(stderr,"set timeout error\n");
    return;
  }

  mysql=mysql_real_connect(mysql,"localhost","user","passwd","qq",0,NULL,0);
  if(mysql){
    printf("connection success\n");
  }else{
    fprintf(stderr,"connection failed\n");
    if(mysql_errno(mysql)){
      fprintf(stderr,"Connection error %d: %d\n",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\n");
    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\n",(unsigned long)mysql_affected_rows(mysql));
  }
  else
  {
    fprintf(stderr,"insert error %d: %s\n",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\n");
    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\n",(unsigned long)mysql_affected_rows(mysql));
  }
  else
  {
    fprintf(stderr,"update error %d: %s\n",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='\0';
   char qs[100];

  if(mysql==NULL)
  {
    fprintf(stderr,"mysql error\n");
    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\n",mysql_error(mysql));
    return 0;
  }
  else
  {
    res_ptr=mysql_store_result(mysql);
    if(res_ptr){
      printf("Search to %lu rows\n",(unsigned long)mysql_num_rows(res_ptr));

      while(sqlrow=mysql_fetch_row(res_ptr)){
    printf("Fetched data...\n");
    tmp=(const char *)&sqlrow[1];
    if(strstr(tmp,user_data)==NULL)
    {
      printf("not exist!\n");
      return 0;
    }
      }
      if(mysql_errno(mysql)){
    fprintf(stderr,"Retrive error: %s\n",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\n");
    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\n",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\n",res_num);
      if(res_num==0)
      {
    return 0;
      }
      else
      {
    printf("Search to %lu rows\n",(unsigned long)mysql_num_rows(res_ptr));
      }

      if(mysql_errno(mysql)){
    fprintf(stderr,"Retrive error: %s\n",mysql_error(mysql));
      } 
    }
    mysql_free_result(res_ptr);
  }
  return 1;
}

void mydb_destory(MYSQL *mysql)
{
  if(mysql==NULL)
  {
    fprintf(stderr,"mysql error\n");
    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,"使用者:\n",10);/*插入文本到缓冲区*/
        gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,text,strlen(text));/*插入文本到缓冲区*/
        gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"\n",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("消息不能为空...!\n");
    }
    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\n",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\n",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\n",name);
    if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
    {
        return 0;
    }

    time (&timep);
    sprintf(time_buffer,"%s\n",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,'\0',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,"服务器:\n",10);/*插入文本到缓冲区*/
                gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,buffer,strlen(buffer));/*插入文本到缓冲区*/
                gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"\n",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的线程不存在或者已经退出。\n",(unsigned int)thr);
        res=0;
    }
    else if(kill_rc == EINVAL)
    {
        printf("发送信号非法。\n");
        res=0;
    }
    else
    {
      printf("ID为%d的线程目前仍然存活。\n",(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\n");
                if(delete_client((void*)(&arrthrreceiveclient),i)==0)
                {
            if(write_to_file("delete_client error")==0)
            {
                exit(-1);
            }
                        exit(-1);
                }
                --arr;
            }
        }
        printf("在线人数:%d\n",arr);
        if(arr<=0)
        {
            printf("没有客户端连接\n");
        }
        else
        {
            int i=0;
            char buf[MAXLEN];
            ssize_t size=0;

            memset(buf,'\0',MAXLEN);
            size=read(STDIN_FILENO,buf,sizeof(buf));
            if(size>0)
            {
                buf[size]='\0';
            }
            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发送成功\n",arrconsocket[i].ipaddr,arrconsocket[i].port);
                }
                else
                {
                    printf("向客户端%s:%d发送失败\n",arrconsocket[i].ipaddr,arrconsocket[i].port);
                }
            }
        }
        sleep(1);
    }
    if(arr>=1)
    {
        char *message;
        int res=1;
        printf("等待线程退出\n");



            if((res=pthread_join(thraccept,(void*)&message))==0)
            {
                printf("%s\n",message);
            }
            else
            {
        if(write_to_file("pthread_join error")==0)
        {
            exit(-1);
        }
        exit(-1);
            }

    }
    else
    {
        printf("没有线程\n");
    }
    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("线程退出\n");
    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\n",name);
    if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
    {
        return 0;
    }

    time (&timep);
    sprintf(time_buffer,"%s\n",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,'\0',sizeof(buffer));//或者使用函数bzero(buffer,20);

        printf("接收套接字:%d\n",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\n",socketcon1);
        exit_thr(&socketcon1);
        arr--;
            pthread_exit("线程退出!");   
        break;
        }
        if(strncmp(buffer,"quit",4)==0)
        {
            fprintf(stdout,"套接字:%d close\n",socketcon1);
            exit_thr(&socketcon1);
        arr--;
            pthread_exit("线程退出!");
        break;

        }
        //printf("buffer:%s\n",buffer);
        buffer[buffer_length]='\0';
        printf("客户端%d:%s\n",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发送成功\n",arrconsocket[i].ipaddr,arrconsocket[i].port);
                }
                else
                {
                    printf("向客户端%s:%d发送失败\n",arrconsocket[i].ipaddr,arrconsocket[i].port);
                }
        }
        }   

    /*------------------------------------------------------------------------*/
        sleep(1);
    }
     printf("接受数据线程结束\n");
}


//处理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\n",++arr);
    printf("连接客户端的套接字:%d\n",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("等待接受的子线程退出\n");



        if((res=pthread_join(thrreceive,(void*)&message))==0)
        {
             printf("%s\n",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

附上效果图:

这里写图片描述

这里写图片描述

这里写图片描述

posted @ 2018-07-03 21:44  带头大哥小白  阅读(269)  评论(0编辑  收藏  举报