正如标题所述,我收到一个奇怪的错误ERROR读取失败:服务器端的成功和ERROR连接:传输端点已经连接
我正在尝试创建一个简单的多线程银行服务器,客户端可以连接并管理帐户。
我是新手,这是我第一次使用套接字和线程,所以请放轻松我。我为没有完全整洁的代码而道歉,但这仍然是一项正在进行中的工作。这是服务器
/*
* 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 accountname\n"; // opens new account unless MAX_ACCOUNTS/_NAME is exceeded or accountName already exists
opt2 = "START accountname\n"; // starts customer session
opt3 = "CREDIT amount\n"; // adds amount to account balance (only valid in customer session)
opt4 = "DEBIT amount\n"; // subtracts amount from account balance (only valid in customer session)
opt5 = "BALANCE\n"; // returns current account balance (only valid in customer session)
opt6 = "FINISH\n"; // ends customer session (only valid in customer session)
opt7 = "EXIT\n"; // disconnets client from server
message = "Here are your options:\n\n";
// 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: %s\n", bank->accounts[i].accountName);
printf("Current Balance: %f\n", bank->accounts[i].balance);
if(bank->accounts[i].session_flag == 1)
printf("Status: In Session\n\n");
else
printf("Status: Not In Session\n\n");
}
// 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 again\n\n";
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 started\n\n";
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 started\n\n";
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 later\n\n";
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 succesful\n\n";
write(sock, message, strlen(message));
}
else
{
message = "You do not have enough funds at this time\n\n";
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 closed\n\n";
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 session\n\n";
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("%s\n", 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.\n\n");
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);
答案 0 :(得分:1)
错误是两次调用connect()的结果。