-
Socket: Client question
Hello,
I am trying to write a client code in C. What I would like to do is create like an Instant message server-client socket. Where I want to have one Server and multiple Clients. I come to a problem that the client may not handle this, but this cannot be true since we do have instant message. I say this because the flow chart of the Socket Server-Client shows that data needs to be send first then receive (google Image: "socket server and client" the attachment on this site does not work).
So I present the problem what if you have 1 Server and 3 Clients.
If one Client writes/sends (lets say "Hello"), then how would the other two Clients receive/read that data (saying "Hello) if Clients writes/sends first. Unless the server is involve with this problem. I hope that makes sense.
I have posted the server code if the server is the problem.
Thanks for your time
Code:
/* This is a server. This code allows multiple client
to connect with the same server's port.
Non-Blocking I/O and select();
Step 1: Setup Address structure
Step 2: Create a socket
Step 3: Bind the socket to the port
Step 4: Listen to the socket
Step 5: Setup an infinite loop to make connections
IBM
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/
index.jsp?topic=%2Frzab6%2Frzab6xnonblock.htm
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MAX_CLIENTS 20
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
fd_set master; //file descriptor master list
fd_set read_fds; //file descriptor temp list for select()
int fdmax; //file descriptor maximum number
int sockfd, newsockfd, portno;//socket, accept, port number
socklen_t clilen;
char buffer[256];//for recv and send of data
int yes=1; //for setsockopt
struct sockaddr_in serv_addr, cli_addr;
struct client{ //struct used to store client information
char name[32]; //contains the client name
int fd; //contains the client file descriptor
};
struct client database[MAX_CLIENTS]; //database of client information
memset(&database, 0, sizeof database);
int numClients = 0; //keep track of how many clients are connected
int i, j; //loop counters
int nbytes; //data recv from the client
char remoteIP[INET6_ADDRSTRLEN + 1];
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
//Check if port is given
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
//Step 1: Setup Address structure
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
//Step 2: Create a socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){
error("ERROR opening socket");
}
printf("The sockfd1 value is: %d\n", sockfd);
//reuse port if it was still in use
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,
&yes,sizeof(int)) == -1) {
error("setsockopt");
exit(1);
}
//Step 3: Bind the socket to the port
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0){
close(sockfd);
}
//Step 4:Listen to the socket
if (listen(sockfd,10) == -1){
error("ERROR on listen");
exit(3);
}
//add file descriptor to master set list
FD_SET(sockfd, &master);
fdmax = sockfd; //as of now, the biggest fd is listener
printf("The fdmax value is: %d\n", fdmax);
printf("Waiting for Client connections...\n");
usleep(1000);
//main while loop: LOOP and check for connection requests, recieved messages
while(1) {
read_fds = master; //copy master list to temp list
//Check to see if the select call failed.
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
//printf("We are at before the main for loop");
printf("The sockfd2 value is: %d\n", sockfd);
//Step 5: Setup an infinite loop to make connections
for(i = 0; i <= fdmax; i++) {
//Check to see if this descriptor is ready
if (FD_ISSET(i, &read_fds)) { //Check if FD is set
//Check to see if this is the listening socket
if (i == sockfd) {//the fd is the listener port [a client is attempting to connect()]
//handle new connections
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
printf("The newsockfd value is: %d\n", newsockfd);
if (newsockfd < 0)
error("ERROR on accept");
else {//accept successful
//Add the new incoming connection to the master read set
FD_SET(newsockfd, &master); //add fd to master list
if (newsockfd > fdmax) { //keep tracks of the FD max
fdmax = newsockfd;
database[numClients].fd = newsockfd; //add connection to array
numClients++; //increment # of client connections
printf("New Connection Accepted - Total Connections: %d\n", numClients);
}
printf("selectserver: new connection from %s on "
"socket %d\n",
inet_ntop(AF_INET, &(cli_addr.sin_addr),
remoteIP, sizeof(remoteIP)),
newsockfd);
}
} else {//not from listener port, must be data from client
// handle data from a client
printf(" Descriptor %d is readable\n", i);
if ((nbytes = recv(i, buffer, sizeof buffer, 0)) <= 0) {
//Checks if any client(s) closed
if (nbytes == 0) {//conection closed
printf("Alert: socket %d hung up\n", i);
} else {
error("recv");
}
close(i); //close sockfd that leaves!
FD_CLR(i, &master); //remove that client from master set
} else {
//we got some data from a client
for(j = 0; j <= fdmax; j++) {
//send to data every client
if (FD_ISSET(j, &master)) {
//except the client that sent the data
if (j != sockfd && j != i) {
if (send(j, buffer, nbytes, 0) == -1) {
error("send");
}
}
}
}
}
} // End handle data from client
} // End got new incoming connection
} // End flag set by a file descriptors
} // End of main while Loop
return 0;
}//End of main
-
You don't have to send data before you receive data.
-
your question isn't clear. but on the client side, it doesn't matter if you have multiple clients or one client. each client operates separately and has a point to point connection to the server. so as far as the clients are concerned, there is only the server and whatever the server sends. are you asking how the client can get keyboard input in parallel with receiving messages from the server? if so, it depends on the operating system. on Linux/Unix you could do it with a single select that is monitoring the keyboard and the socket. on windows you need to do something different, maybe with a keyboard input thread that sends to the server, and a separate socket receiving thread that receives messages from the server. then it depends on your user interface how you display what you input and what you receive.
-
dmh2000,
If you do not mind if I could give an example what I am trying to understand. All I want is a multiple instant message where if one guy sends a message everyone gets that message..
Lets say we have three people Instant messaging.
person1 sends "Hello" on his terminal to the server, then the server sends that message to person2 and person3. Thus person2 and person3's terminal displays "Hello".
I hope that makes sense.
If I run a simple client code such as the one below it will wait. I understand that fgets() will make the client wait, but I do not think that will fix the problem.
Code:
#include <stdio.h>#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
while(1){//Edited While Loop
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
}//Edited: While Loop
close(sockfd);
return 0;
}
Thanks for your time.
-
Moved to Networking/Device Communication.