我个人相信很多人都想自己实现一个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使用的系统默认版本