简体   繁体   中英

C Programming multiple threads on XUbuntu

I'm trying make the program run multiple threads to it connects to different ports. I successfully made it work on a single thread but not multiple.

Below I have posted the code of what I'm using on XUbuntu.

server.c

#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

// File io storing in lof file
#include "server_portLog.h"
// Thread used to create sockets
#include "sockets_pthread.h"

#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {  
// Server port number
//int portNumber = atoi(argv[1]);

// sockfd: ip-address sockit, newsockfd: socket from resiving     client , portNum: Wich port will be lisenting, num_bytes: recived data     from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & recive values from the server
char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);

// Geting all ports from comand line parameters and creating a socket for each
int numPorts = argc - 1;
struct port varPorts[numPorts];
pthread_t portsSockets[numPorts];
for (int i = 0; i < numPorts; i++) {
    varPorts[i].portNumber = atoi(argv[i + 1]);
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_create(&portsSockets[i], &attr, createSocket, &varPorts[i]);
}

// Infinet loop too keep liseting even after connection to client closes
while (1) {
    // After that all the ports entered have a socket of their own the program runs them paralel together to see if any client tries to connect with one of the ports
    for (int i = 0; i <= numPorts; i++) {
        pthread_join(&portsSockets[i], NULL);
        /* Start listening for the clients (thread blocks) */
        if (listen(varPorts[i].sockfd, 5) != 0) {
            printf("Error: listen() failed for port: %d \n", varPorts[i].portNumber);
            //return 3;
        }

        // Accepting connection from client & creating socket with that client data
        newsockfd = accept(varPorts[i].sockfd, (struct sockaddr *)&cli_addr, &clilen);
        if (newsockfd < 0) {
            printf("Error: accept() failed for port: %d \n", varPorts[i].portNumber);
            //return 4;
        }

        /* To send recive data */
        // Clearing buffer
        memset(buffer, 0, BUFFER_SIZE);
    
        // Show data recived from client
        num_bytes = recv(newsockfd, buffer, BUFFER_SIZE-1, 0);
        if (num_bytes < 0) {
            printf("Error: recv() failed for port: %d \n", varPorts[i].portNumber);
            //return 5;
        }

        // Checking version of server if LOGFILE it creares a file to store the ports
        #if defined LOGFILE
        // Checking if user wrote a fileName for the logs or going to use the defualt log file
        if (argc == 3) {
            char *textFile = argv[argc-1];
            serverLogFile_Custom(buffer, textFile);
        }
        else {
            serverLogFile_Defualt(buffer);
        }
        #else
        // Print the port numbers that connect to server
        printf("Recieved: Client using port- %s to connect \n", buffer);
        #endif
        // Closing connection with client
        close(newsockfd);
    }
}
return 0;
 }

Sockets_pthreads.h

   #include <pthread.h>

struct port {
int portNumber;
int sockfd;
};

 void* createSocket(void* portNumber) {
// sockfd: ip-address sockit, newsockfd: socket from resiving    client , portNum: Wich port will be lisenting, num_bytes: recived data    from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & recive values from the server
//char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);

struct port *portStruct = (struct port*) portNumber;
// Creating a new sockit with ip-Protocol_tcp
    // Parameters: Internet-domain, socket-stream, TCP-protocol
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
    printf("Error: Failed to open socket for port: %d \n", portStruct->portNumber);
    //return 1;
}

// Seting all bits in padding-field to 0 
memset(&serv_addr, 0, sizeof(serv_addr));
// Initializing socket in sockaddr_in (stucture)
serv_addr.sin_family = AF_INET; // Seting family-Internet
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portStruct->portNumber); // Setting portNum (passed in command line)

// Binding the address-structure to the socket
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
    printf("Error: bind() failed for port: %d \n", portStruct->portNumber);
    //return 2;
}
// Geting sockfd
portStruct->sockfd = sockfd;

pthread_exit(0);
 }

Problem is not clear what needs to be implemented. If various ports sockets have to accept, then it has to happen in thread function as well as recv call. In server function there are accept and recv calls which are blocking by default.

The main function should wait for connections. Upon receiving a request from the client, you create a thread that will handle this specific connection. So you will create the threads in the loop, meaning, you can theoretically have an infinite number of threads. However, you can add a little logic to limit the number of threads that are existing at a particular time (thread pool).

So your main loop can look like this:

 while (1) {
        // accept: wait for a connection request 
        childfd = accept(parentfd, (struct sockaddr *) &clientaddr, (socklen_t *) &clientlen);
        if (childfd < 0){
            fprintf(stderr,"ERROR on accept");
            continue;
        }

        hostaddrp = inet_ntoa(clientaddr.sin_addr);
        if (hostaddrp == NULL){
            fprintf(stderr,"ERROR on inet_ntoa\n");
            continue;
        }
        fprintf(stdout,"server established connection with client\n");

        pthread_t new_thread;
        newSock     = malloc(1);
        *newSock    = childfd;
        if( pthread_create( &new_thread , NULL ,  server_thread , (void*) newSock) < 0){
            bzero(logMsg, MAXSTRING);
            sprintf(logMsg, "Thread for connection %d could not be created",childfd);
            fprintf(stderr, "%s\n", logMsg);
            continue;
        }
        fprintf(stdout, "thread created for connection %d\n", childfd);
    }

The server_thread function could look like:

void *server_thread(void* clientSock){
    int                 childfd = *(int*)clientSock;
    char                buf[MAXLINE];       // message buffer
    int                 n;                  // message byte size
    char                logMsg[MAXSTRING];
    size_t              siz_failresp;

    // read: read input string from the client
    bzero(buf, MAXLINE);
    n = (int) read(childfd, buf, MAXLINE);
    if (n < 0){
        sprintf(logMsg, "ERROR reading from socket");
        fprintf(stderr,"%s", logMsg);
        close(childfd);
        fprintf(stdout, "Client %d disconnected \n=================\n", childfd);
        //Free the socket pointer
        free(clientSock);
        return NULL;
    }

    // else, do processing of data received...
    // ...................
}

There may be unused variables here above... I just got this code from one of my projects, just removing parts that do not concern you :-)

Hope it helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM