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!\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应用程序相关推荐
- linux gtk 仿qq聊天程序
使用环境: Linux操作系统,且装有TCP/IP,及POP3,SMTP协议,运行服务端要装有MYSQL数据库. 创建数据库: 启动数据库 service mysqld start 进行数据库 mys ...
- 仿QQ聊天程序(java)
仿QQ聊天程序(java) 2014年03月17日 15:52:47 标签: java / 聊天 / 仿QQ 90246 仿QQ聊天程序 转载出处: https://blog.csdn.net/u01 ...
- qq服务器 udp协议,基于UDP傳输协议的实时通信系统的开发(仿qq聊天程序).doc
基于UDP傳输协议的实时通信系统的开发(仿qq聊天程序) 基于UDP传输协议的实时通信系统的开发(仿qq聊天程序) 摘 要 互联网的高速发展正改变着人类的生活,它的多姿多彩正一点一滴的渗透到人们生活的 ...
- java聊天程序论文_【基于java的仿qq聊天程序的设计与实现论文最终版材料】
基于java的仿qq聊天程序的设计与实现(论文)(最终版) <基于java的仿qq聊天程序的设计与实现(论文).doc>由会员分享,可免费在线阅读全文,更多与<基于java的仿qq聊 ...
- linux下仿qq聊天源代码,Linux+glade(GTK+)+C语言+mysql的模仿QQ聊天工具(完善版)...
[实例简介] 之前发布的版本没有带myql的运行库,好多人运行不了,这次我重新打包一份 包含了mysql 的include 和 lib库 ,这个版本大家可以在本地轻松的编译,文件包内包含了mysql的 ...
- java 飞秋 demo_Java实现仿QQ、飞秋聊天程序
[实例简介] 用java CS 模式实现的简单版的java实现的仿qq聊天程序,有上线下线弹窗提醒.聊天.上传头像.自动更新好友列表.自动加载好友信息.发送消息.发送文件等功能,减压后的文件夹下附有说 ...
- 转载:仿QQ聊天软件2.0版
仿QQ聊天软件2.0版 这是大神的地址:牟尼的专栏 http://blog.csdn.net/u012027907 详细的过程本人没看,但是看见他的实现效果,相当诱人! 上次课设做了Java版 ...
- 循序渐进实现仿QQ界面(一):园角矩形与双缓冲贴图窗口
印象里仿QQ界面的程序应该有很多,搜了一下,虽然出来一大堆,排除了重复的,却只有两三个,没我想象的好.经常看到CSDN上有人问,QQ这个功能怎么实现,那个界面怎么实现,归纳了一下,决定写这么一个仿QQ ...
- vc循序渐进实现仿QQ界面(一):圆角矩形与双缓冲贴图窗口
印象里仿QQ界面的程序应该有很多,搜了一下,虽然出来一大堆,排除了重复的,却只有两三个,没我想象的好.经常看到CSDN上有人问,QQ这个功能怎么实现,那个界面怎么实现,归纳了一下,决定写这么一个仿Q ...
最新文章
- ios 简书 获取通讯录信息_iOS 13获取用户通讯录需要注意的
- php多进程实现 亲测
- B00013 字符串哈希函数
- Python下载中国数据库大会(DTCC2020)PPT全集
- shell脚本判断上一个命令是否执行成功
- vimb java,我可以让vim接受\b而不是\lt;和\gt ;?
- 盘点 12 款让开发效率“飞起”的 VS Code 插件
- 自制EDL工程线进坚果R1手机9008端口刷机记录
- python绘制网格地图_「GIS教程」Python-GeoPandas地图、专题地图绘制
- STC89C52引脚图
- 收藏备用丨CAD快捷键大全
- win7系统使用命令行定时关机的操作方法
- 奈何心是安定心,命总是流浪命
- vue项目使用mand mobile check选择项组点击选中,选中的列表延迟一位问题
- 桌面计算器The C++ Programming Language程序解析
- Markdown | 最具有效率的写作工具一次性掌握
- DeFi+NFT+DAO,MIGO打造区块链新金融雏形
- 无所不能的Java系列文章
- 电影网站 php asp,asp电影网址导航大全 V20201218
- 有机晶体数据库_福利干货 | 对晶体学数据库来个大盘点吧!