错误读取失败:成功(简单多线程服务器)c编程



正如标题所述,我收到一个奇怪的错误错误读取失败:服务器端成功,连接错误:传输端点已连接

我正在尝试制作一个简单的多线程银行服务器,客户端可以连接到该服务器并管理帐户。

我是新手,这是我第一次使用套接字和线程,所以请对我宽容一点。我很抱歉代码没有完全整理好,但这仍然是一项正在进行的工作。这是服务器

    /*
 * makeSocket function creates, initializes, and binds a socket on a given port
 *
 * revieces a void* pointing to a port number
 *
 * returns socket descriptor
 */
int makeSocket(void* port)
{
    //uint16_t portNum = *(uint16_t*) port;
    int sock;
    struct sockaddr_in name;
    // Create the socket
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
        error("ERROR opening socket");
    // bzero may also work here
    memset(&name, 0, sizeof(struct sockaddr_in));

    /*Prepare the sockaddr_in struct
     */
    name.sin_family = AF_INET;
    name.sin_port = htons(PORT_NUM);                // htons change the bit format of a number to network type
    name.sin_addr.s_addr = INADDR_ANY;
    // Bind socket
    if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0)
        error("ERROR on binding");
    printf(" socket made ");
    return sock;
}
/*
 * prompt function writes bank prompt to a given socket
 *
 * reciieves a socket descriptor as an int
 *
 * does not return anything
 */
void prompt(int sock)
{
    char *message, *opt1, *opt2, *opt3, *opt4, *opt5, *opt6, *opt7;
    // initialize options
    opt1 = "OPEN accountnamen";        // opens new account unless MAX_ACCOUNTS/_NAME is exceeded or accountName already exists
    opt2 = "START accountnamen";       // starts customer session 
    opt3 = "CREDIT amountn";           // adds amount to account balance (only valid in customer session)
    opt4 = "DEBIT amountn";            // subtracts amount from account balance (only valid in customer session)
    opt5 = "BALANCEn";                 // returns current account balance (only valid in customer session)
    opt6 = "FINISHn";                  // ends customer session (only valid in customer session)
    opt7 = "EXITn";                    // disconnets client from server
    message = "Here are your options:nn";
    // display options
    write(sock, message, strlen(message));
    write(sock, opt1, strlen(opt1));
    write(sock, opt2, strlen(opt2));
    write(sock, opt3, strlen(opt3));
    write(sock, opt4, strlen(opt4));
    write(sock, opt5, strlen(opt5));
    write(sock, opt6, strlen(opt6));
    write(sock, opt7, strlen(opt7));
    return;
}
/*
 * printThread is a function that displays all bank information roughly every PRINT_RATE seconds
 *
 * printThread takes no arguements because the bank is a global variable
 *
 * there is no return value
 */
void *printThread(void* theGoods)
{
    Bank *bank = (Bank*)theGoods;
    int i;
    while(1)
    {
        // try locking bank if succesfull print all account information and then unlock
        if (pthread_mutex_trylock(&bank->bank_lock) == 0)
        {
            i = 0;
            // print all account information
            for(i; i < MAX_ACCOUNTS; i++)
            {
                printf("Account ID: %sn", bank->accounts[i].accountName);
                printf("Current Balance: %fn", bank->accounts[i].balance);
                if(bank->accounts[i].session_flag == 1)
                    printf("Status: In Sessionnn");
                else
                    printf("Status: Not In Sessionnn");
            }
            // unlock bank_lock and wait untill it is time to print again
            pthread_mutex_unlock(&bank->bank_lock);
            sleep(PRINT_RATE);
        }
        // if bank_lock is locked wait 2 seconds and then try again
        else
            sleep(2);
    }
}
/*
 * clientServerThread interacts with each client creating a bank client interface
 *
 * requires a socket descriptor as an arg to interact with client
 *
 * thread does not return exits when client decides
 */
void *clientServerThread(void *socket_desc)
{
    int sock = *(int*)socket_desc;
    int bytesRead;
    int exitFlag = 0;
    char *message;
    char *accountInSession;
    int accountInSessionNum = MAX_ACCOUNTS + 5;
    char acName[MAX_ACCOUNT_NAME];
    char buffer[MAX_ACCOUNT_NAME + 6];
    char optionBuffer[MAX_ACCOUNT_NAME + 6];
    bzero(buffer, MAX_ACCOUNT_NAME + 6);
    bzero(optionBuffer, MAX_ACCOUNT_NAME + 6);
    // great the new client and prompt them with the options
    message = "Greetings! Welcome to Riordan&Hess bank how may we help you?n";
    write(sock, message, strlen(message));
    prompt(sock);
    sleep(3);
    while(exitFlag == 0)
    {
        // read client choice from socket
        bytesRead = read(sock, buffer, MAX_ACCOUNT_NAME + 5);
        if (bytesRead <= 0)
            error("ERROR read failed");
        // convert user input to all lower case for comparison
        int i = 0;
        while (buffer[i])
        {
            buffer[i] = tolower(buffer[i]);
            i++;
        }
        // check if client chose opt1 OPEN
        strcpy(optionBuffer, "open");
        if ((strncmp(buffer, optionBuffer, 4)) == 0)
        {
            // check if MAX_ACCOUNTS is exceeded
            if (bank.total_accounts = MAX_ACCOUNTS)
            {
                i = 0;
                strncpy(acName, buffer+5, MAX_ACCOUNT_NAME);    
                // check if matching account name already exists
                for(i; i <= MAX_ACCOUNTS; i++)
                {   
                    int accountLen;
                    accountLen = sizeof(bank.accounts[i].accountName) - 5;
                    // if matching account name already exists ask client for new name
                    if (strncmp(bank.accounts[i].accountName, acName, MAX_ACCOUNT_NAME) == 0)       
                    {
                        message = "This account name is taken please try againnn";
                        write(sock, message, strlen(message));
                        prompt(sock);
                    }
                    // if there are no previous matches and an empty spot is found create account
                    else if (bank.accounts[i].exists == 0)
                    {
                        // set bank & account mutex
                        pthread_mutex_lock (&bank.bank_lock);
                        pthread_mutex_lock (&bank.accounts[i].account_lock);
                        // initialize account
                        bank.total_accounts++;
                        bank.accounts[i].exists = 1;
                        bank.accounts[i].balance = 0;
                        bank.accounts[i].session_flag = 1;
                        // create session
                        accountInSession = acName;
                        accountInSessionNum = i;
                        message = "Account created and session startednn";
                        write(sock, message, strlen(message));
                        // unlock bank mutex
                        pthread_mutex_unlock (&bank.bank_lock);
                        prompt(sock);
                    }
                }
            }
            // inform client that MAX_ACCOUNTS was exceeded
            else
            {
                message = "We are sorry to inform you that all of our accounts are in use. Please come back and try later";
                write(sock, message, strlen(message));
            }
        }
        // check if client chose Start
        strcpy(optionBuffer, "start");
        if ((strncmp(buffer, optionBuffer, 5)) == 0)
        {   
            // check if client is already in session
            if(accountInSessionNum <= MAX_ACCOUNTS)
            {
                message = "You are already in an account session please exit and then try again";
                write(sock, message, strlen(message));
                prompt(sock);
            }
            if (accountInSessionNum > MAX_ACCOUNTS)
            {
                // check if matching account name exists
                for(i; i <= MAX_ACCOUNTS; i++)
                {
                    int accountLen;
                    strncpy(acName, buffer+6, MAX_ACCOUNT_NAME);                            // store account name on stack
                    // if matching account exists try and begin a session
                    if (strncmp(bank.accounts[i].accountName, acName, MAX_ACCOUNT_NAME) == 0)       
                    {
                        message = "Account found ";
                        write(sock, message, strlen(message));
                        // if the account is not in session begin session
                        if(bank.accounts[i].session_flag == 0)
                        {
                            // lock account mutex and start session
                            pthread_mutex_lock (&bank.accounts[i].account_lock);
                            accountInSessionNum = i;
                            accountInSession = acName;
                            bank.accounts[i].session_flag = 1;
                            message = "Session startednn";
                            write(sock, message, strlen(message));
                        }
                        // if the account is in session infrom client and tell them to try again
                        else
                        {
                            message = "Account requested is already in session please try again laternn";
                            write(sock, message, strlen(message));
                        }
                    }
                }
            }
            else
            {
                // tell client no matching account exists
                message = "No matching account exists";
                write(sock, message, strlen(message));
                prompt(sock);
            }
        }
        // client has chosen exit disconnect
        strcpy(optionBuffer, "exit");
        if ((strncmp(buffer, optionBuffer, 4)) == 0)
        {
            exitFlag = 1;
            // check if client is in session->disconnect
            if(accountInSessionNum <= MAX_ACCOUNTS)
            {
                bank.accounts[accountInSessionNum].session_flag = 0;
                pthread_mutex_unlock(&bank.accounts[accountInSessionNum].account_lock);
                accountInSession = NULL;
                accountInSessionNum = MAX_ACCOUNTS + 5;
            }               
                //diconnect
        }
        // client has chosen credit add to balance
        strcpy(optionBuffer, "credit");
        if ((strncmp(buffer, optionBuffer, 6)) == 0)
        {
            char *amount;
            float creditAmount;
            if (accountInSessionNum <= MAX_ACCOUNTS)
            {
                // copy amount to new variab;e
                strncpy(amount, buffer+6, 20);
                creditAmount = (float) atof(amount);
                // add amount to balance and inform client
                bank.accounts[accountInSessionNum].balance += creditAmount;
                message = "Credit succesful";
                write(sock, message, strlen(message));
                prompt(sock);
            }
            else
            {
                // tell client that they are not in a session
                message = "You are not currently in an account session please START";
                write(sock, message, strlen(message));
                prompt(sock);
            }
        }
        // client has chosen debit subtract from balance
        strcpy(optionBuffer, "debit");
        if ((strncmp(buffer, optionBuffer, 5)) == 0)
        {
            char *amount;
            float debitAmount;
            // check if client is in session
            if (accountInSessionNum <= MAX_ACCOUNTS)
            {
                strncpy(amount, buffer+6, 20);
                debitAmount = (float) atof(amount);
                // check if client's balance is greater than the sum requested
                if (bank.accounts[accountInSessionNum].balance > debitAmount)
                {
                    bank.accounts[accountInSessionNum].balance -= debitAmount;
                    message = "Debit succesfulnn";
                    write(sock, message, strlen(message));
                }
                else
                {
                    message = "You do not have enough funds at this timenn";
                    write(sock, message, strlen(message));
                }
                prompt(sock);
            }
            else
            {
                // tell client that they are not in a session
                message = "You are not currently in an account session please START";
                write(sock, message, strlen(message));
                prompt(sock);
            }
        }
        // client has requested balance
        strcpy(optionBuffer, "balance");
        if ((strncmp(buffer, optionBuffer, 7)) == 0)
        {
            if((accountInSessionNum <= MAX_ACCOUNTS))
            {
                // tell client the balance of accountInSession
                sprintf(message, "Current Balance: %f", bank.accounts[accountInSessionNum].balance);
                write(sock, message, strlen(message));
                prompt(sock);
            }
            else
            {
                // tell client the must be in session
                message = "You are not currently in an account session please START";
                write(sock, message, strlen(message));
                prompt(sock);
            }
        }
        strcpy(optionBuffer, "finish");
        if ((strncmp(buffer, optionBuffer, 6)) == 0)
        {
            // if account in session end session
            if(accountInSessionNum <= MAX_ACCOUNTS)
            {
                // end session and inform user
                accountInSession = NULL;
                accountInSessionNum = MAX_ACCOUNTS + 5;
                message = "Session closednn";
                write(sock, message, strlen(message));
                // Release mutex
                pthread_mutex_unlock (&bank.accounts[i].account_lock);
            }
            else
            {
                // tell client no matching account exists
                message = "You are not currently in an account sessionnn";
                write(sock, message, strlen(message));
                prompt(sock);
            }
        }
    }
    // exit thread
}
/*
 * sessionAcceptorThread creates and listens to a socket spawing clientServerThead each time a client connects
 *
 * recieves bank pointer NOT USED
 *
 * does not return
 */
void *sessionAcceptorThread(void* bankList)
{
    //Bank bank = *(Bank*)bankList;
    int socket;
    int connection;
    struct sockaddr_in peer_Addr;
    int addrLen;
    // create and bind socket and wait for incoming connections
    socket = makeSocket((void *)PORT_NUM);
    if(listen(socket, LISTEN_BACKLOG) < 0)
        error("ERROR on listening");
    addrLen = sizeof(struct sockaddr_in);
    pthread_t client_server_thread;
        // for each connection spawn clientServerThread
        while(connection = accept(socket, (struct sockaddr *) &peer_Addr,(socklen_t*) &addrLen))
        {
            int TID;
            TID = pthread_create(&client_server_thread, NULL, clientServerThread, (void *) &connection);
            if (TID < 0)
                error("ERROR could not create serv/client thread");
            else
                printf(" WE GOT A CUSTOMER ");
        }
        if (connection < 0)
            error("ERROR accept failed");

    //pthread_exit(NULL);
}
int main()
{   
    int SA_threadID;
    int print_threadID;
    uint16_t portNum = PORT_NUM;
    //initialize Bank struct with default values
    //createBank(&bank);
    Bank *bank = (Bank*) malloc(sizeof(struct _Bank));
    // build thread status variables for pthread_exit to use later
    void* threadStatus0;
    void* threadStatus1;
    // build thread handles for pthread_create
    pthread_t SAthread;
    pthread_t POthread;
    pthread_t* SAthreadHandle = &SAthread;
    pthread_t* POthreadHandle = &POthread;
    // build blank pthread attribute structs and initialize them
    pthread_attr_t SAthreadAttr;
    pthread_attr_t POthreadAttr;
    pthread_attr_init(&SAthreadAttr);
    pthread_attr_init(&POthreadAttr);
    // set the initialized attribute struct so that the pthreads created will be joinable
    pthread_attr_setdetachstate(&SAthreadAttr, PTHREAD_CREATE_JOINABLE);
    pthread_attr_setdetachstate(&POthreadAttr, PTHREAD_CREATE_JOINABLE);
    // set the initialized attribute struct so that the pthreads created will be joinable
    pthread_attr_setscope(&SAthreadAttr, PTHREAD_SCOPE_SYSTEM);
    pthread_attr_setscope(&POthreadAttr, PTHREAD_SCOPE_SYSTEM);
    // build the pthreads
    SA_threadID = pthread_create(&SAthread, &SAthreadAttr, sessionAcceptorThread, (void *)bank);
    if (SA_threadID < 0)
    {
        printf("errer");
        error("ERROR could not create session_acceptor thread");
    }
    print_threadID = pthread_create(&POthread, &POthreadAttr, printThread, (void *)bank);
    if (print_threadID < 0)
        error("ERROR could not create print thread");
    printf("end of main");
    pthread_join(SAthread, &threadStatus0);
    //sleep(10);

}

和客户端

    */
/*
 *serverOut gets server output and prints to client.
 */
void* serverOut(void* serverName)
{
    char* server = (char*) serverName;
    char bufferS[256];
    printf("Getting server output.n");
    while(read(sock, bufferS, sizeof(bufferS)) > 0)
    {
        printf("%sn", bufferS);
        sleep(2);
    }
    sleep(2);
    pthread_exit(NULL);
}
/*
 *userOut gets user input and writes to server.
 *If user types 'exit', then they are disconnected.
 */
void* userOut(void* ignore)
{
    printf("Sending user input.n");
    char bufferU[256];
    while(1)
    {
        scanf(" %[^n]}", bufferU);
        int i;
        while(bufferU[i])
        {
            bufferU[i] = tolower(bufferU[i]);
            i++;
        }
        write(sock, bufferU, strlen(bufferU) + 1);
/*      if(streq(bufferU, "quit")) //scrap
        {
            pthread_kill(thread, SIGINT);
            printf("Disconnected from server.n");
            exit(0);
        }*/
        if(strcmp(bufferU, "exit") == 0)
        {
            pthread_kill(thread, SIGINT);
            printf("Client disconnected from the server.n");
            exit(0);
        }
        sleep(2);
    }
    sleep(2);
    pthread_exit(NULL);
}
int main(int argc, char *argv[])
{           
    int sock = -1;
    int portno = -1; //server port to connect to
    int n = -1; //utility variable for monitoring reading/writing from/to the socket
    char buffer[256]; //char array to store data going to and coming from server
    struct sockaddr_in dest; //struct that holds address info for building socket
    struct hostent *host; //struct that holds infor about a machine's address
    if(argc < 3) //if the user didn't enter enough arguments, complain and exit
    {
        fprintf(stderr, "usage %s hostname port.  Specify server host.n", argv[0]);
        exit(0);
    }
    portno = atoi(argv[2]); //parse text as an int
    host = gethostbyname(argv[1]); //look up IP address that matches
    if(host == NULL)
    {
        fprintf(stderr,"ERROR finding host.n");
        exit(0);
    }
    char* serverName = argv[1];
    // Create the socket
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0) //if it doesn't work, complain and exit
    {
        error("ERROR opening socket.n");
    }
    printf("Sock created.n");
    printf("Please wait while we connect you to the server.nn");
    memset(&dest, 0, sizeof(struct sockaddr_in));
    //bzero((char *)&dest, sizeof(dest));
    //bzero line above may also work
    //Prepare the sockaddr_in struct
    dest.sin_family = AF_INET; //set a flag to indicate the type of network address
    dest.sin_port = htons(5625);  //htons change the bit format of a number to network type
    //dest.sin_addr.s_addr = 128.6.13.230;
    if((host = gethostbyname(serverName)) == NULL)
    {
        printf("ERROR getting address information.n");
    }
    else
    {   
        // do a raw copy of the bytes that represent the server's IP address in 
        //   the 'serverIPAddress' struct into our serverIPAddressInfo struct
        bcopy((char *)host->h_addr, (char *)&dest.sin_addr.s_addr, host->h_length);
    }
    int connectionStatus;
    connectionStatus = connect(sock, (const struct sockaddr*) &dest, sizeof(dest));
/*  int x = 0; //scrap
    while( (x = connect(sock, (const struct sockaddr*) &dest, sizeof(dest)) ) ) //scrap
    {
        printf("Attempting to connect to %s...n", serverName);
        perror("");
        sleep(3);
    }*/
    while(connectionStatus != 0)
    {
        printf("Establishing connection to %s.n", serverName);
        connectionStatus = connect(sock, (const struct sockaddr*) &dest, sizeof(dest));
        perror("");
        sleep(2);
    }
    if (connect(sock, (struct sockaddr *)&dest, sizeof(dest)) != 0 )
    {
        error("ERROR connecting.n");
    }
    //We are now connected to the server.
    printf("You have connected to the server.n");
    pthread_create(&thread, NULL, serverOut, serverName);
    pthread_detach(thread);
    pthread_create(&handler, NULL, &userOut, NULL);
    pthread_detach(thread);
    while(write(sock, "0", 2) == 2)
    {
        sleep(1);
    }
    pthread_kill(thread, SIGINT);
    pthread_kill(handler, SIGINT);
    close(sock);

错误是两次调用connect()的结果。

最新更新