我正在尝试建立一个简单的多线程银行服务器。客户可以连接并更改帐户。
我已经设置了套接字和线程,一切似乎都运行正常。但我似乎无法在任何一端使读/写工作。
在客户端,我有两个线程,一个用于管理写入,另一个用于读取。 奇怪的是,在客户端,只要一个线程写入套接字,另一个线程就会读取刚刚写入该套接字的内容。
所以我的问题是为什么客户端读取(sock,bufferU,strlen(bufferU)给我相同的字符串写入(sock,bufferS,strlen(bufferS)刚刚发送。考虑到他们甚至不共享相同的堆栈不确定怎么了。
这是客户端
/*
*serverOut gets server output and prints to client.
*/
void* serverOut(void* serverName)
{
printf("Getting server output.\n");
char* server = (char*) serverName;
char bufferS[256];
int bytesRead;
while(keepRunning)
{
// zero out buffer
memset(bufferS, '0', 256);
sleep(2);
while(read(sock, bufferS, sizeof(bufferS)) > 0)
{
printf("%s\n", bufferS);
}
if (bytesRead <= 0)
error("ERROR read failed");
}
printf("serverOut ending");
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];
int bytesWritten;
sleep(3);
while(keepRunning)
{
// zero out buffer
memset(bufferU, '0', 256);
sleep(2);
scanf(" %[^\n]}", bufferU);
bytesWritten = write(sock, bufferU, strlen(bufferU));
if (bytesWritten <= 0)
error("ERROR read failed");
if(strcmp(bufferU, "exit") == 0)
{
keepRunning = 0;
printf("Disconnecting from the server.\n");
exit(0);
}
}
printf("userOut ending");
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
int read_threadID, write_threadID;
int connectionStatus;
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
pthread_t thread;
pthread_t handler;
// Check if the user entered enough agruments
if(argc < 3)
{
fprintf(stderr, "usage %s hostname port. Specify server host.\n", argv[0]);
exit(0);
}
// store important info on stack
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 and infor user
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");
// zero out sockadd_in struct
//bzero((char *)&dest, sizeof(dest));
memset(&dest, 0, sizeof(struct sockaddr_in));
// 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
if((host = gethostbyname(serverName)) == NULL)
printf("ERROR getting address information.\n");
else
bcopy((char *)host->h_addr, (char *)&dest.sin_addr.s_addr, host->h_length);
// try to connect a first time
connectionStatus = connect(sock, (const struct sockaddr*) &dest, sizeof(dest));
// if first try fails try every two seconds
while(connectionStatus != 0)
{
printf("Establishing connection to %s.\n", serverName);
connectionStatus = connect(sock, (const struct sockaddr*) &dest, sizeof(dest));
perror("");
sleep(2);
}
if (connectionStatus < 0 )
error("ERROR connecting.\n");
// We are now connected to the server.
printf("You have connected to the server.\n");
// build thread status variables for pthread_exit to use later
void* readThreadStatus;
void* writeThreadStatus;
// build thread handles for pthread_create
pthread_t readThread;
pthread_t writeThread;
pthread_t* readThreadHandle = &readThread;
pthread_t* writeThreadHandle = &writeThread;
// build blank pthread attribute structs and initialize them
pthread_attr_t readThreadAttr;
pthread_attr_t writeThreadAttr;
pthread_attr_init(&writeThreadAttr);
pthread_attr_init(&readThreadAttr);
// set the initialized attribute struct so that the pthreads created will be joinable
pthread_attr_setdetachstate(&readThreadAttr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setdetachstate(&writeThreadAttr, PTHREAD_CREATE_JOINABLE);
// set the initialized attribute struct so that the pthreads created will be joinable
pthread_attr_setscope(&readThreadAttr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setscope(&writeThreadAttr, PTHREAD_SCOPE_SYSTEM);
// build the pthreads and check for errors
read_threadID = pthread_create(&readThread, &readThreadAttr, serverOut, (void *)readThreadStatus);
if (read_threadID < 0)
error("ERROR could not create session_acceptor thread");
write_threadID = pthread_create(&writeThread, &writeThreadAttr, userOut, (void *)writeThreadStatus);
if (write_threadID < 0)
error("ERROR could not create print thread");
// join communication threads
pthread_join(readThread, &readThreadStatus);
pthread_join(writeThread, &writeThreadStatus);
close(sock);
printf("You have disconnected from the server.\n");
return 0;
}
这是服务器(我为包含所有这些代码而道歉,不确定错误在哪里)
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
printf(" Greeting the Customer");
message = "Greetings! Welcome to Riordan&Hess bank how may we help you?\n";
bytesRead = write(sock, message, strlen(message) + 1);
printf("wrote %d", bytesRead);
prompt(sock);
while(keepRunning)
{
// zero out buffer
memset(buffer, '0', MAX_ACCOUNT_NAME + 6);
// read client choice from socket
bytesRead = read(sock, buffer, MAX_ACCOUNT_NAME + 5);
if (bytesRead <= 0)
error("ERROR read failed");
printf("PAST READ");
// 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)
{
// change global variable to in form client session threads to shut down
keepRunning = 0;
// 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;
}
}
// 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);
}
}
}
pthread_exit(NULL);
}
/*
* 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;
while(keepRunning)
{
// 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
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 and check for errors
SA_threadID = pthread_create(&SAthread, &SAthreadAttr, sessionAcceptorThread, (void *)bank);
if (SA_threadID < 0)
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");
pthread_join(SAthread, &threadStatus0);
printf("Server succefully shut down");
}
答案 0 :(得分:0)
就是这样,我只是盖过了导致我的全局变量 相信我是连接的,因为它是主要的。但是当 线程试图访问它未初始化的全局变量。现在 至于为什么它回应我不知道
你刚刚得到了印象&#34;它回应了#34;因为未初始化(即零初始化)全局write(sock, bufferU, strlen(bufferU))
的{{1}}没有写入服务器,而是直接写入文件描述符0;在类UNIX系统上,这通常出现在您的终端上。