2014-10-01 92 views
0

我试图用下面的代码实现一个多线程的tcp服务器。Linux C:libmysqlclient.so.18.0.0中的segfault错误4

int main(int argc , char *argv[]) 
{ 
    int socket_desc , client_sock , c , *new_sock; 
    struct sockaddr_in server , client; 

    //Create socket 
    socket_desc = socket(AF_INET , SOCK_STREAM , 0); 
    if (socket_desc == -1) 
    { 
     printf("Could not create socket"); 
    } 
    puts("Socket created"); 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(8888); 

    //Bind 
    if(bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) 
    { 
     //print the error message 
     perror("bind failed. Error"); 
     return 1; 
    } 
    puts("bind done"); 

    //Listen 
    listen(socket_desc , 3); 

    //Accept and incoming connection 
    puts("Waiting for incoming connections..."); 
    c = sizeof(struct sockaddr_in); 

    while((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))) 
    { 
     puts("Connection accepted"); 

     pthread_t sniffer_thread; 
     new_sock = malloc(1); 
     *new_sock = client_sock; 

     if(pthread_create(&sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0) 
     { 
      perror("could not create thread"); 
      return 1; 
     } 

     //Now join the thread , so that we dont terminate before the thread 
     //pthread_join(sniffer_thread , NULL); 
     puts("Handler assigned"); 
    } 

    if (client_sock < 0) 
    { 
     perror("accept failed"); 
     return 1; 
    } 

    return 0; 
} 

/* 
* This will handle connection for each client 
* */ 
void *connection_handler(void *socket_desc) 
{ 
    //Get the socket descriptor 
    int newsockfd = *(int*)socket_desc; 
    int read_size; 
    char *message , buffer[2000]; 
    int n; 
    struct auth details; 
    char* reply; 

    char cmd[100] = {0};  
    //Receive a message from client 
    while((read_size = recv(newsockfd , buffer , 2000 , 0)) > 0) 
    { 
     printf("Incoming data: %s", buffer); 

     if(parseData(cmd, buffer, "/", "-"))  /* If received data is compliant */ 
     { 
      details = authenticate(cmd); 
      if (details.verified)     // If said user can execute this command. 
      { 
       reply = execute(cmd);    // Execute. 
       n = write(newsockfd, reply, strlen(reply)); 
       if (n < 0) { error("ERROR writing to socket"); } 

       free(reply); 
       reply = NULL; 

      } 
      else          // Authentication failed. 
      { 
       n = write(newsockfd, details.error_msg, strlen(details.error_msg)); 
       if (n < 0) { error("ERROR writing to socket"); } 
       else{ 
        if(debug) printf("sent: %s\n", details.error_msg); 
       } 
      } 
     } 
    } 


    if(read_size == 0) 
    { 
     puts("Client disconnected"); 
     fflush(stdout); 
    } 
    else if(read_size == -1) 
    { 
     perror("recv failed"); 
    } 

    //Free the socket pointer 
    free(socket_desc); 

    return 0; 
} 

的authenticate函数在一个实现文件中定义:

struct auth authenticate(const char* const command) 
{ 
    struct auth data; 
    char* db_pwd; 
    char* perm; 
    char* username = "testUser"; 
    char query[200] = {0}; 

    data.verified = FALSE; 
    data.error_msg = ""; 

    printf("in auth\n"); 
    MYSQL_ROW row; 
    snprintf(query, 200, "SELECT password FROM userlist WHERE user='%s'", username); 
    if ((row = mysql_fetch_row(run_query(query))))  // if user is on list 
    { 
     db_pwd = row[0]; 

     if(!strcmp(db_pwd, password)) 
     { 
      if (!(strcmp(command, "test"))) 
      { 
       data.verified = TRUE; 
      } 
     } 
    } 
    return data; 
} 

我有这个程序(主)与相同的实现文件的工作单线程版本,分割故障与仅发生多线程版本。

  • 我在做我的代码错了吗?
  • 我应该如何进行调试?

任何想法,将不胜感激。

回答

1

阅读MySQL C API的文档,特别是§ 23.8.12 C API Threaded Function Descriptions它内部使用套接字连接到mysqld服务器进程,因此您必须序列化所有MySQL函数。

因此,定义您的全局互斥锁,并保护所有使用该互斥锁执行mysql调用的函数(从请求获取所有响应行)。更好的是,设计你的应用程序,以便只有一个线程(通常是主线程)使用mysql函数。

编译所有警告和调试信息(gcc -Wall -g)。使用调试器(gdb)也许valgrind

如果不熟悉mutexes,你可能想读pthread tutorial

+0

感谢您的及时答复。 您是否建议是否为每个新的accept()代替多线程方法分派新的进程(两次以避免调用wait())会更好?这样我可以避免互斥对吧? – Zaxter 2014-10-01 11:55:01

+1

我没有这样说过。你可以有一个多线程的方法,但是你应该序列化(通过一个互斥体)所有的MySQL函数的使用。不要害怕互斥体(它们在多线程应用程序中是必不可少的) – 2014-10-01 11:58:51