• Linux下C编写基本的多线程socket服务器


    不想多说什么,会搜这些东西的都是想看代码的吧。

    一开始不熟悉多线程的时候还在想怎么来控制一个线程的结束,后来发现原来有pthread_exit()函数可以直接在线程函数内部调用结束这个线程。

    开始还想初始化一个pthread_t thread_fd[MAX]数组来存储开启的线程,然后用一个栈存储那些未分配的数组元素(thread_fd[index]=0)的index,跟缓存的思维相似,不过实在是想多了。

    废话不多说,直接上代码,服务器和客户端都已经编译通过,正常运行,有基本的容错能力,不过也只是最基本的。

    服务器:

      1 /*
      2  * multi_thread_socket_server.c
      3  *
      4  *  Created on: Mar 14, 2014
      5  *      Author: nerohwang
      6  */
      7 #include<stdlib.h>
      8 #include<pthread.h>
      9 #include<sys/socket.h>
     10 #include<sys/types.h>       //pthread_t , pthread_attr_t and so on.
     11 #include<stdio.h>
     12 #include<netinet/in.h>      //structure sockaddr_in
     13 #include<arpa/inet.h>       //Func : htonl; htons; ntohl; ntohs
     14 #include<assert.h>          //Func :assert
     15 #include<string.h>          //Func :memset
     16 #include<unistd.h>          //Func :close,write,read
     17 #define SOCK_PORT 9988
     18 #define BUFFER_LENGTH 1024
     19 #define MAX_CONN_LIMIT 512     //MAX connection limit
     20 
     21 static void Data_handle(void * sock_fd);   //Only can be seen in the file
     22 
     23 int main()
     24 {
     25     int sockfd_server;
     26     int sockfd;
     27     int fd_temp;
     28     struct sockaddr_in s_addr_in;
     29     struct sockaddr_in s_addr_client;
     30     int client_length;
     31 
     32     sockfd_server = socket(AF_INET,SOCK_STREAM,0);  //ipv4,TCP
     33     assert(sockfd_server != -1);
     34 
     35     //before bind(), set the attr of structure sockaddr.
     36     memset(&s_addr_in,0,sizeof(s_addr_in));
     37     s_addr_in.sin_family = AF_INET;
     38     s_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);  //trans addr from uint32_t host byte order to network byte order.
     39     s_addr_in.sin_port = htons(SOCK_PORT);          //trans port from uint16_t host byte order to network byte order.
     40     fd_temp = bind(sockfd_server,(struct scokaddr *)(&s_addr_in),sizeof(s_addr_in));
     41     if(fd_temp == -1)
     42     {
     43         fprintf(stderr,"bind error!
    ");
     44         exit(1);
     45     }
     46 
     47     fd_temp = listen(sockfd_server,MAX_CONN_LIMIT);
     48     if(fd_temp == -1)
     49     {
     50         fprintf(stderr,"listen error!
    ");
     51         exit(1);
     52     }
     53 
     54     while(1)
     55     {
     56         printf("waiting for new connection...
    ");
     57         pthread_t thread_id;
     58         client_length = sizeof(s_addr_client);
     59 
     60         //Block here. Until server accpets a new connection.
     61         sockfd = accept(sockfd_server,(struct sockaddr_*)(&s_addr_client),(socklen_t *)(&client_length));
     62         if(sockfd == -1)
     63         {
     64             fprintf(stderr,"Accept error!
    ");
     65             continue;                               //ignore current socket ,continue while loop.
     66         }
     67         printf("A new connection occurs!
    ");
     68         if(pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd)) == -1)
     69         {
     70             fprintf(stderr,"pthread_create error!
    ");
     71             break;                                  //break while loop
     72         }
     73     }
     74 
     75     //Clear
     76     int ret = shutdown(sockfd_server,SHUT_WR); //shut down the all or part of a full-duplex connection.
     77     assert(ret != -1);
     78 
     79     printf("Server shuts down
    ");
     80     return 0;
     81 }
     82 
     83 static void Data_handle(void * sock_fd)
     84 {
     85     int fd = *((int *)sock_fd);
     86     int i_recvBytes;
     87     char data_recv[BUFFER_LENGTH];
     88     const char * data_send = "Server has received your request!
    ";
     89 
     90     while(1)
     91     {
     92         printf("waiting for request...
    ");
     93         //Reset data.
     94         memset(data_recv,0,BUFFER_LENGTH);
     95 
     96         i_recvBytes = read(fd,data_recv,BUFFER_LENGTH);
     97         if(i_recvBytes == 0)
     98         {
     99             printf("Maybe the client has closed
    ");
    100             break;
    101         }
    102         if(i_recvBytes == -1)
    103         {
    104             fprintf(stderr,"read error!
    ");
    105             break;
    106         }
    107         if(strcmp(data_recv,"quit")==0)
    108         {
    109             printf("Quit command!
    ");
    110             break;                           //Break the while loop.
    111         }
    112         printf("read from client : %s
    ",data_recv);
    113         if(write(fd,data_send,strlen(data_send)) == -1)
    114         {
    115             break;
    116         }
    117     }
    118 
    119     //Clear
    120     printf("terminating current client_connection...
    ");
    121     close(fd);            //close a file descriptor.
    122     pthread_exit(NULL);   //terminate calling thread!
    123 }

    外加客户端:

     1 /*
     2  * socket_client.c
     3  *
     4  *  Created on: Mar 15, 2014
     5  *      Author: nerohwang
     6  */
     7 #include<stdlib.h>
     8 #include<sys/socket.h>
     9 #include<sys/types.h>       //pthread_t , pthread_attr_t and so on.
    10 #include<stdio.h>
    11 #include<netinet/in.h>      //structure sockaddr_in
    12 #include<arpa/inet.h>       //Func : htonl; htons; ntohl; ntohs
    13 #include<assert.h>          //Func :assert
    14 #include<string.h>          //Func :memset
    15 #include<unistd.h>          //Func :close,write,read
    16 #define SOCK_PORT 9988
    17 #define BUFFER_LENGTH 1024
    18 int main()
    19 {
    20     int sockfd;
    21     int tempfd;
    22     struct sockaddr_in s_addr_in;
    23     char data_send[BUFFER_LENGTH];
    24     char data_recv[BUFFER_LENGTH];
    25     memset(data_send,0,BUFFER_LENGTH);
    26     memset(data_recv,0,BUFFER_LENGTH);
    27 
    28     sockfd = socket(AF_INET,SOCK_STREAM,0);       //ipv4,TCP
    29     if(sockfd == -1)
    30     {
    31         fprintf(stderr,"socket error!
    ");
    32         exit(1);
    33     }
    34 
    35     //before func connect, set the attr of structure sockaddr.
    36     memset(&s_addr_in,0,sizeof(s_addr_in));
    37     s_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1");      //trans char * to in_addr_t
    38     s_addr_in.sin_family = AF_INET;
    39     s_addr_in.sin_port = htons(SOCK_PORT);
    40 
    41     tempfd = connect(sockfd,(struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
    42     if(tempfd == -1)
    43     {
    44         fprintf(stderr,"Connect error! 
    ");
    45         exit(1);
    46     }
    47 
    48     while(1)
    49     {
    50         printf("Please input something you wanna say(input "quit" to quit):
    ");
    51         gets(data_send);
    52         //scanf("%[^
    ]",data_send);         //or you can also use this
    53         tempfd = write(sockfd,data_send,BUFFER_LENGTH);
    54         if(tempfd == -1)
    55         {
    56             fprintf(stderr,"write error
    ");
    57             exit(0);
    58         }
    59 
    60         if(strcmp(data_send,"quit") == 0)  //quit,write the quit request and shutdown client
    61         {
    62             break;
    63         }
    64         else
    65         {
    66             tempfd = read(sockfd,data_recv,BUFFER_LENGTH);
    67             assert(tempfd != -1);
    68             printf("%s
    ",data_recv);
    69             memset(data_send,0,BUFFER_LENGTH);
    70             memset(data_recv,0,BUFFER_LENGTH);
    71         }
    72     }
    73 
    74     int ret = shutdown(sockfd,SHUT_WR);       //or you can use func close()--<unistd.h> to close the fd
    75     assert(ret != -1);
    76     return 0;
    77 }
  • 相关阅读:
    linux常用命令
    Hibernate常用API以及使用说明
    Hibernate使用套路,新手请进
    git 完全讲解 无废话,包含在myeclipse中使用,包括解决冲突
    Spring使用事务增加的注解实现方
    java.lang.ClassCastException: com.sun.proxy.$Proxy27 cannot be cast to com.bbk.n002.service.QuestionService
    使用aspectJ实现Spring AOP的两种方式
    用Diff和Patch工具维护源码
    opennebula 补丁制作与补丁升级
    IPMI总结
  • 原文地址:https://www.cnblogs.com/nerohwang/p/3602233.html
Copyright © 2020-2023  润新知