[英]read/write over a socket c programming
I am trying to set up a simple multi-threaded bank server. 我正在尝试建立一个简单的多线程银行服务器。 Where clients can connect and make changes to accounts.
客户可以在其中连接并更改帐户的位置。
I have set up the sockets and thread and everything appears to be working fine. 我已经设置了套接字和线程,一切似乎都工作正常。 But I can not seem to get the read/write to work on either end.
但是我似乎无法使读/写在任何一端都能正常工作。
On the client side I have two threads one for managing write and one for read. 在客户端,我有两个线程,一个用于管理写入,另一个用于读取。 The strange part is that on the client side whenever one thread writes to the socket the other thread reads what was just written to that socket.
奇怪的是,在客户端,每当一个线程向套接字写入内容时,另一线程就读取刚刚写入该套接字的内容。
So my question is why is the client read(sock, bufferU, strlen(bufferU) give me the same string that write(sock, bufferS, strlen(bufferS) just sent. considering they dont even share the same stack not sure whats going on. 所以我的问题是为什么客户端read(sock,bufferU,strlen(bufferU)给我的字符串与write(sock,bufferS,strlen(bufferS)刚刚发送的)相同,考虑到它们甚至不共享同一堆栈,所以不确定是怎么回事。
here is the client 这是客户
/*
*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;
}
here is the server (I apologize for including all this code just not sure where the error would be) 这是服务器(我很抱歉包含所有这些代码,只是不确定错误会在哪里)
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");
}
that was it I simply overshadowed my global variable leading me to believe that i was connected because it was in the main.
就是这样,我只是掩盖了我的全局变量,使我相信我是有联系的,因为它是主要的。 but when the thread tried to access the global variable it was not initialized.
但是,当线程尝试访问全局变量时,它尚未初始化。 now as to why it was echoing i have no idea
现在,为什么它回声我不知道
You just got the impression "it was echoing" because the write(sock, bufferU, strlen(bufferU))
to the uninitialized (ie zero-initialized) global sock
didn't write to the server, but rather directly to file descriptor 0; 您刚刚得到的印象是“它正在回显”,因为对未初始化(即零初始化)的全局
sock
的write(sock, bufferU, strlen(bufferU))
并未写入服务器,而是直接写入文件描述符0。 on UNIX-like systems this typically appears on your terminal. 在类似UNIX的系统上,这通常显示在您的终端上。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.