我个人相信很多人都想自己实现一个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!\n");//登陆到客户端窗口程序execv("./log_client", NULL);}else{printf("failed\n");}printf("用户名是:%s",username);  printf("\n");  printf("密码是:%s\n",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!\n");    }else{printf("failed\n");}}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\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","zhangsan","123456","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.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 1024typedef 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,'\0',sizeof(buffer));int buffer_length=read(_socketcon,buffer,MAXLEN-1);if(buffer_length<=0){printf("空数据\n");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\n");socketcon=socket(AF_INET,SOCK_STREAM,0);if(socketcon<0){perror("socket error\n");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\n",socketcon);int res_con=connect(socketcon,(struct sockaddr*)(&client_addr),sizeof(struct sockaddr));if(res_con!=0){perror("connect error\n");exit(0);}printf("连接成功!\n");/*if(pthread_create(&thrreceive,NULL,fun_thrreceive,&socketcon)!=0){perror("pthread_create error\n");exit(0);}sleep(1);*///while(1){char *buf;int size=0;//memset(buf,'\0',sizeof(buf));buf=S_text;size=strlen(buf);if(size>0){buf[size]='\0';}else if(size==0){printf("不能为空\n");int sendmsg_len=write(socketcon,"NULL",4);if(sendmsg_len==4){printf("发送退出码成功!\n");}else{printf("发送失败!\n");}//break;}else{perror("read error\n");//break;}int sendmsg_len=write(socketcon,buf,size);if(sendmsg_len>0){printf("发送成功,客户端套接字:%d\n",socketcon);}else{printf("发送失败!\n");}printf("%s\n",buf);if(strcmp(buf,"quit\n")==0){close(socketcon);pthread_kill(thrreceive,SIGKILL);exit(0);}sleep(2);//}int len=write(socketcon,"NULL",4);if(len==4){printf("发送成功,客户端套接字:%d\n",socketcon);}else{printf("发送失败!\n");}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 10const 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的线程不存在或者已经退出。\n",(unsigned int)thr);res=0;}else if(kill_rc == EINVAL){printf("发送信号非法。\n");res=0;}else{printf("ID为0x%x的线程目前仍然存活。\n",(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,'\0',sizeof(buffer));//或者使用函数bzero(buffer,20);printf("接收套接字:%d\n",socketcon1);buffer_length=read(socketcon1,buffer,MAXLEN-1);if(buffer_length<0){printf("接收客户端失败了\n");}else if(strncmp(buffer,"NULL",4)==0){int i=0,k=0;printf("线程退出\n");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\n")==0){int i=0;int k=0;fprintf(stdout,"套接字:%d close\n",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\n",buffer);buffer[buffer_length]='\0';printf("客户端%d:%s\n",socketcon1,buffer);sleep(1);}printf("接受数据线程结束\n");
}//删除杀死的线程
int delete_client(void *fp,int num)
{/*int pthreadnum=0;int thrreceiveclientcount=0;//接收消息的线程IDint 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\n");exit(5);}   else{printf("accept success\n");printf("ip:%s,port:%d\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));}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){perror("pthread_create error\n");exit(6);}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{printf("pthread_join error:%d\n",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\n");  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\n");  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\n");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\n");exit(2);}int listen_socket=listen(service_socket,10);//监听套接字if(listen_socket<0)//失败的处理{perror("listen error\n");exit(3);}pthread_t thraccept;//创建的线程数组//pthread_create创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后,就开始运行相关的线程函数if(pthread_create(&thraccept,NULL,fun_thraccepthander,&service_socket)!=0){perror("pthread_create error\n");exit(4);}sleep(1);
/*pthread_t thrfile;if(pthread_create(&thrfile,NULL,fun_thrfile,&service_socket)!=0){perror("pthread_create error\n");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\n");if(delete_client((void*)(&arrthrreceiveclient),i)==0){printf("delete_client error\n");exit(6);}--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{perror("read error\n");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);}}}//pthread_join(id1,&a1);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{printf("pthread_join error:%d\n",res);}}else{printf("没有线程\n");}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使用的系统默认版本

linux 实现仿QQ应用程序相关推荐

  1. linux gtk 仿qq聊天程序

    使用环境: Linux操作系统,且装有TCP/IP,及POP3,SMTP协议,运行服务端要装有MYSQL数据库. 创建数据库: 启动数据库 service mysqld start 进行数据库 mys ...

  2. 仿QQ聊天程序(java)

    仿QQ聊天程序(java) 2014年03月17日 15:52:47 标签: java / 聊天 / 仿QQ 90246 仿QQ聊天程序 转载出处: https://blog.csdn.net/u01 ...

  3. qq服务器 udp协议,基于UDP傳输协议的实时通信系统的开发(仿qq聊天程序).doc

    基于UDP傳输协议的实时通信系统的开发(仿qq聊天程序) 基于UDP传输协议的实时通信系统的开发(仿qq聊天程序) 摘 要 互联网的高速发展正改变着人类的生活,它的多姿多彩正一点一滴的渗透到人们生活的 ...

  4. java聊天程序论文_【基于java的仿qq聊天程序的设计与实现论文最终版材料】

    基于java的仿qq聊天程序的设计与实现(论文)(最终版) <基于java的仿qq聊天程序的设计与实现(论文).doc>由会员分享,可免费在线阅读全文,更多与<基于java的仿qq聊 ...

  5. linux下仿qq聊天源代码,Linux+glade(GTK+)+C语言+mysql的模仿QQ聊天工具(完善版)...

    [实例简介] 之前发布的版本没有带myql的运行库,好多人运行不了,这次我重新打包一份 包含了mysql 的include 和 lib库 ,这个版本大家可以在本地轻松的编译,文件包内包含了mysql的 ...

  6. java 飞秋 demo_Java实现仿QQ、飞秋聊天程序

    [实例简介] 用java CS 模式实现的简单版的java实现的仿qq聊天程序,有上线下线弹窗提醒.聊天.上传头像.自动更新好友列表.自动加载好友信息.发送消息.发送文件等功能,减压后的文件夹下附有说 ...

  7. 转载:仿QQ聊天软件2.0版

    仿QQ聊天软件2.0版 这是大神的地址:牟尼的专栏 http://blog.csdn.net/u012027907 详细的过程本人没看,但是看见他的实现效果,相当诱人!     上次课设做了Java版 ...

  8. 循序渐进实现仿QQ界面(一):园角矩形与双缓冲贴图窗口

    印象里仿QQ界面的程序应该有很多,搜了一下,虽然出来一大堆,排除了重复的,却只有两三个,没我想象的好.经常看到CSDN上有人问,QQ这个功能怎么实现,那个界面怎么实现,归纳了一下,决定写这么一个仿QQ ...

  9. vc循序渐进实现仿QQ界面(一):圆角矩形与双缓冲贴图窗口

    印象里仿QQ界面的程序应该有很多,搜了一下,虽然出来一大堆,排除了重复的,却只有两三个,没我想象的好.经常看到CSDN上有人问,QQ这个功能怎么实现,那个界面怎么实现,归纳了一下,决定写这么一个仿Q ...

最新文章

  1. ios 简书 获取通讯录信息_iOS 13获取用户通讯录需要注意的
  2. php多进程实现 亲测
  3. B00013 字符串哈希函数
  4. Python下载中国数据库大会(DTCC2020)PPT全集
  5. shell脚本判断上一个命令是否执行成功
  6. vimb java,我可以让vim接受\b而不是\lt;和\gt ;?
  7. 盘点 12 款让开发效率“飞起”的 VS Code 插件
  8. 自制EDL工程线进坚果R1手机9008端口刷机记录
  9. python绘制网格地图_「GIS教程」Python-GeoPandas地图、专题地图绘制
  10. STC89C52引脚图
  11. 收藏备用丨CAD快捷键大全
  12. win7系统使用命令行定时关机的操作方法
  13. 奈何心是安定心,命总是流浪命
  14. vue项目使用mand mobile check选择项组点击选中,选中的列表延迟一位问题
  15. 桌面计算器The C++ Programming Language程序解析
  16. Markdown | 最具有效率的写作工具一次性掌握
  17. DeFi+NFT+DAO,MIGO打造区块链新金融雏形
  18. 无所不能的Java系列文章
  19. 电影网站 php asp,asp电影网址导航大全 V20201218
  20. 有机晶体数据库_福利干货 | 对晶体学数据库来个大盘点吧!

热门文章

  1. 坚果PRO3搭载Android,意外!坚果Pro3喜提Android10操作系统更新
  2. 关于Android Studio查看SQLite数据库
  3. 20190531-复盘
  4. 使用手环代替NFC标签实现多屏协同
  5. 2012移动开发者大会成都站
  6. c语言大顶堆算法,数据结构之大顶堆
  7. 华为,在行星的十字路口
  8. 河南人一定要看的关于自己城市的说法(转自校内网)
  9. python简单网格五子棋_python制作简单五子棋游戏
  10. Oxford 102 Flowers数据集