when i run both client and server i get this as result:
on server
Server is on
Client: XXX.X.X.X accepted
(that's the point that the program pauses until I type ctrl+C in client)
I try to get in while
I get in while
Client
AI Choise:Scissor
AI:Wins ratio 0,Looses ratio 0,Ties ratio 1
I get in while
Client
AI Choise:Scissor
AI:Wins ratio 0,Looses ratio 0,Ties ratio 2
on client
1)--> Paper
2)--> Scissor
3)--> Rock
4)--> Quit
^C
my code:
Server:
int main(int argc, char *argv[]){
printf("\nServer is on\n");
int sockfd, newsockfd, portno;
socklen_t clilen;
int Client_Choice;
struct sockaddr_in serv_addr, cli_addr;
int n,Who_Wins;
int ai_wins=0,ai_looses=0,ties=0,total=0,ai_win_ratio=0,ai_looses_ratio=0,ai_ties_ratio;
time_t t;
srand((unsigned) time(&t));
if (argc < 2) {
fprintf(stderr,"\nERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){
error("\nERROR opening socket\n",sockfd);
}
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);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
error("\nERROR on binding\n",sockfd);
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen);
if (newsockfd < 0){
error("\nERROR on accept\n",sockfd);
}
char *cli_IP = malloc(sizeof(cli_addr.sin_addr.s_addr));
if (!cli_IP){
error("\nCould not allocate memory for conversion.\n",sockfd);
}
inet_ntop( AF_INET , &cli_addr.sin_addr.s_addr , cli_IP , INET_ADDRSTRLEN );
printf("\nClient: %s accepted\n",cli_IP);
printf("I try to get in while");
while(Client_Choice!=4){
printf("I get in while");
n= read( newsockfd, &Client_Choice, sizeof(Client_Choice) );
if(n < 0) {
error("\nERROR reading from socket\n",sockfd);
}
.
.
.
}
close(newsockfd);
close(sockfd);
return 0;
}
client
int main(int argc, char *argv[]){
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
int send;
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\n");
}
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\n");
}
while(send < 1 ||send > 4){
printf("\n\t1)--> Paper\n\t2)--> Scissor\n\t3)--> Rock\n\t4)--> Quit\n");
scanf("%d",&send);
n = write(sockfd,&send,sizeof(send));
if (n < 0){
error("ERROR writing to socket\n");
}
n = read(sockfd,&send,sizeof(send));
if (n == 0){
error("ERROR reading from socket\n");
}
}
close(sockfd);
return 0;
}
Your server is blocked waiting the message from the client. You have not reserved resources for dealing with several clients and only have a single process serving a single client (using the connection socket from accept(2)). That's the reason of it to appear blocking. In a normal server scenario, a new process is spawned by a fork(2) system call to deal with the socket obtained from accept(2) while the main process continues to accept(2) connections on the socket used for accepting new connections. As you are dealing with two sockets in server, but not attending the socket descriptor where accept(2) connections come in, it appears to be blocked, but it is actually ready to accept the commands from the active client. This is what is called a sequential server (it doesn't allow a connection before the first one terminates).
By the way, send is uninitialized before use in first while (send < 1 || send > 4) sentence so in case you get it casually equal to 2 (for example) you won't get client code into the while at all. This is only a point, probably there will be more. Why have you used different names for the message type interchanged between server and client? this makes more difficult to search for errors.
Related
I am checking the communication between 2 entities (A and B) for their presence. A is a server and B is a client. When the server is up and running, it waits for connections and when B starts, it sends a message "Available" every one second. Now, the problem is, when I terminate the B program( ctrl+c or press the close button of the terminal), the server A does not recognise and still continues its operation. I would like for it to display message like "B is no more available" or "communicating partner is off". I understand TCP would be a best fit for the connection oriented communication. Please suggest me the changes to incorporate the display message on server A, when B is closed.
PS: amateur in socket programming
EDIT1: Managed to display the Message. However, since the server is designed to listen to many connections, I would like to make it accept the connections and not end the loop. Any guidance here would be useful.
SERVER(A) TCP SERVER
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
// create socket and get file descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
clilen = sizeof(cli_addr);
// bind the host address using bind() call
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
perror("ERROR on binding\n");
exit(1);
}
// start listening for the clients,
// here process will go in sleep mode and will wait for the incoming connection
listen(sockfd, 5);
// accept actual connection from the client
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
// inside this while loop, implemented communication with read/write or send/recv function
//printf("start");
while (1) {
bzero(buffer,256);
n = read(newsockfd, buffer, 255);
if (n < 0){
perror("ERROR in reading from socket");
exit(1);
}
if (n == 0){
perror("Client has abruptly ended\n");
close(sockfd);
exit(1);
}
printf("client said: %s \n", buffer);
n = write(newsockfd, buffer, strlen(buffer));
if (n < 0){
perror("ERROR in writing to socket");
exit(1);
}
// escape this loop, if the client sends message "quit"
// if (!bcmp(buffer, "quit", 4))
// break;
}
return 0;
}
CLIENT(B) TCP CLIENT
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[]) {
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
portno = 5001;
// create socket and get file descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server = gethostbyname("127.0.0.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);
// connect to server with server address which is set above (serv_addr)
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR while connecting");
exit(1);
}
// inside this while loop, implement communicating with read/write or send/recv function
while (1) {
strcpy(buffer,"Available");
n = write(sockfd,buffer,strlen(buffer));
if (n < 0){
perror("ERROR while writing to socket");
exit(1);
}
bzero(buffer,256);
n = read(sockfd, buffer, 255);
if (n < 0){
perror("ERROR while reading from socket");
exit(1);
}
printf("server replied: %s \n", buffer);
// escape this loop, if the server sends message "quit"
//if (!bcmp(buffer, "quit", 4))
// break;
sleep(1);
}
return 0;
}
Please anybody tell me how to handle that issue?
When the client closes the TCP connection, the server's call to read(newsockfd) will return 0 to indicate that the connection has closed. At that point, the server should close(newsockfd), print your "Client has gone away message", and not use newsockfd anymore (i.e. either the server program should exit, or, more usefully, it should just break out of its while(1)-loop and go back to calling accept() again, so that the next time a client runs it too can connect to the server)
For instance, there are several requests in a file, and I read them then send to server line by line by using write function. However, there is only one response from server, and I cannot read the whole requests to server. Is there anyone who can help me to figure out this problem. Thank you so much!
There is server code:
<pre> <code>
int main(int argc, char *argv[]){
int sockfd, newsockfd, n;
unsigned int clientLen;
char bufferSK[256];
struct sockaddr_in serv_addr,cli_addr;
FILE *fp = NULL;
//create an endpoint for bind, listen and accept.
sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd < 0) {
printf("Failed to create socket for server!\n");
}
bzero((char *)&serv_addr, sizeof(serv_addr));
//set the address of server.
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port_number);
//bind the port with server address
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("Error on bind!\n");
}
listen(sockfd,port_number);
printf("\nI am listening for connection\n");
clientLen = sizeof(cli_addr);
//using accept function to accept the connection from client
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clientLen);
if (newsockfd < 0) {
printf("Error on accept!\n");
}
printf("\nI have accepted your connection\n");
bzero(bufferSK,256);
n = read (newsockfd, bufferSK,255);
if (n < 0) {
printf("Error reading message from socket\n");
}
printf("\nThe message from client is: %s",bufferSK);
n = write(newsockfd, "SERVER: I got your message!\n", 27);
if (n < 0) {
printf("Error writing to socket\n");
}
close(newsockfd);
close(sockfd);
return 0;
}
there is client code:
<pre> <code>
FILE *fp_queue;
int main(int argc, char *argv[]){
int sockfd, server_port_number, n, connectRes;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
//Three parameters must be provided.
if(argc != 4){
fprintf(stderr, "Usage: %s server_host_name server_port_number file_path\n",argv[0]);
exit(0);
}
server_port_number = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//create socket for client.
if (sockfd < 0) {
printf("Failed to create socket for client\n");
exit(0);
}
server = gethostbyname(argv[1]);
if (server == NULL) {
printf("Oops! There is no such host!\n");
exit(0);
}
//set the attributes of server as zeros.
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
//copy the server address from serv_addr.sin_addr.s_addr to server->h_adddr.
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(server_port_number);
connectRes = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (connectRes < 0) {
printf("Error connection\n");
exit(0);
}
printf("connect successfully\n");
fp_queue = fopen(argv[3], "r");
if (fp_queue == NULL) {
printf("Failed open client file %s\n", argv[3]);
exit(1);
}
bzero(buffer, 256);
while ((fgets(buffer,sizeof(buffer),fp_queue)) != NULL) {
buffer[strlen(buffer) - 1] = '\0';
printf("buffer is %s\n", buffer);
n = write(sockfd, buffer, strlen(buffer));
if (n < 0) {
printf("Error write to socket\n");
}
bzero(cliBuffer, 256);
n = read(sockfd, buffer, 256);
if (n <0) {
printf("Error read from socket\n");
}
printf("%s\n", buffer);
}
close(sockfd);
return 0;
}
There are at least 2 design issues in the code.
The server code receives one request, sends a response and then server terminates. If you want to process more requests over one connection then the server code must contain a loop like a client has. The server code should contain something like
while ((n = read (newsockfd, bufferSK, 255) > 0) {
printf("\nThe message from client is: %s",bufferSK);
n = write(newsockfd, "SERVER: I got your message!\n", 27);
if (n < 0) {
printf("Error writing to socket\n");
break;
}
}
close(newsockfd);
The next problem is that TCP is a stream oriented protocol and your code does not consider that. The stream orientation means that protocol does not keep message boundaries. When a sender calls write("a"); write("b") the receiver may get characters in two separate reads or it may receive 2 characters in one read. To overcome the problem the peers must define some protocol how to determine message boundaries. Usually client sends a message length at begin of message or a control character is used as message boundary or messages have fixed length.
I have written a sample socket program in C on Linux.
The server is single process server.
The program is simple where the server is running and the client connects to the server waiting on accept() call.
When the server accepts the client request it sends some string to the client using write call.
Server Code:
#define MAXHOSTNAME 256
#define MAX_CONN 10
void single_process_server(unsigned int portNumber)
{
int listenSockFd, acceptSockFd, portNo;
socklen_t clilen;
char buffer[256] = "Connected";
struct sockaddr_in srvInfo;
int n;
char sysHost[MAXHOSTNAME+1]; // Hostname of this computer we are running on
if((listenSockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
close(listenSockFd);
error("ERROR opening socket");
}
bzero((char *) &srvInfo, sizeof(srvInfo));
portNo = portNumber;
srvInfo.sin_family = AF_INET;
srvInfo.sin_addr.s_addr = htonl(INADDR_ANY);
srvInfo.sin_port = htons(portNo);
if (bind(listenSockFd, (struct sockaddr *) &srvInfo, sizeof(srvInfo)) < 0)
{
close(listenSockFd);
error("ERROR on binding");
}
listen(listenSockFd,5);
while(1)
{
clilen = sizeof(srvInfo);
if((acceptSockFd = accept(listenSockFd, (struct sockaddr *) &srvInfo, &clilen)) < 0)
{
error("ERROR on accept");
}
if((n = write(acceptSockFd,buffer,255)) < 0)
{
error("ERROR writing to socket");
}
close(acceptSockFd);
}
close(listenSockFd);
}
int main(int argc, char* argv[])
{
unsigned int portNo= 0;
portNo = 444;
single_process_server(portNo);
return(0);
}
The client receives the string using read call.
Client Code:
void simple_internet_client(char hostip[], unsigned int portNo)
{
int sockFd, portno, n;
struct sockaddr_in srvInfo;
struct hostent *server;
char buffer[256];
portno = portNo;
if((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
error("ERROR opening socket");
}
if((server = gethostbyname(hostip)) == NULL)
{
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &srvInfo, sizeof(srvInfo));
srvInfo.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&srvInfo.sin_addr.s_addr, server->h_length);
srvInfo.sin_port = htons(portno);
if(connect(sockFd,(struct sockaddr *) &srvInfo,sizeof(srvInfo)) < 0)
error("ERROR connecting");
{
bzero(buffer,256);
if((n = read(sockFd,buffer,255)) < 0)
error("ERROR reading from socket");
printf("Socket read = %s\n", buffer);
}
close(sockFd);
}
main(int argc, char* argv[])
{
char hostip[50] = {0};
unsigned int portNo= 444;
printf("B. Provide the host name or IP:\n");
scanf("%s",&hostip);
simple_internet_client(hostip, portNo);
return(0);
}
When I run the client(./clientdemo) at some intervals then the client receives whatever string the server sends.
But when I run the client multiple times through some script then the client remains stuck up at read() call and does not receive what the server has sent.
Simply speaking when the client connects to the server at faster rate then the server writes to the socket at same rate.But the client is not able to read the data written on the socket and remains stuck up on the read() call.
What may be the cause of this and why client is not able to read data from socket at same rate as server writes to it?
I have a server-client system (concurrent server). I have different clients on different machines. I am trying to send a notification to particular clients. However, I have a problem as the clients all have the same socket descriptor. On both computers, the clients have a socket descriptor of 3 and at the server a sd of 5. Can someone please tell me how I can identify these different clients and why is this happening?
int main(int argc, char *argv[]) {
pid_t pid;
int buff_size = 1024;
char buff[buff_size];
int listen_fd, client_conn;
struct sockaddr_in serv_addr;
int server_port = 5001;
char remote_file[255];
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror("Socket cannot be opened");
exit(1);
}
/*Turning off address checking in order to allow port numbers to be
reused before the TIME_WAIT. Otherwise it will not be possible to bind
in a very short time after the server has been shut down*/
int on = 1;
int status = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
(const char *) &on, sizeof(on));
if (status == -1) {
perror("Failed to Reuse Address on Binding");
}
// Initialise socket structure
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY; // Accept connections from any address
serv_addr.sin_port = htons(server_port);
// Bind the host address
if (bind(listen_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))
< 0) {
perror("ERROR on binding");
exit(1);
}
// Start listening for the clients, here process will
// go in sleep mode and will wait for the incoming connection
listen(listen_fd, 5);
while (1) {
//Accepting client connection
client_conn = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (client_conn < 0) {
perror("Client was not accepted...");
exit(1);
}
if ((pid = fork()) == 0) {
close(listen_fd);
bzero(buff, buff_size);
while ((bytes_read = read(client_conn, buff, buff_size)) > 0) {
fclose(file);
}
}
//Terminating child process and closing socket
close(client_conn);
exit(0);
bzero(buff, buff_size);
}
//parent process closing socket connection
close(client_conn);
}
return 0;
}
After the server forks a child it does close(client_conn). When accept assigns a socket descriptor to the new connection, it uses the lowest closed descriptor. Since you closed the socket earlier, it can be used for the next client that comes in.
This isn't a problem, because the connections are being managed by the child processes. They each have their own descriptor 5, and they don't interfere with each other.
You can get the client address & port returned to you by accept. Currently you are passing a null
client_conn = accept(listen_fd, (struct sockaddr *) NULL, NULL);
however just add a few lines like
struct sockaddr_in serv_addr, cli_addr;
int len = sizeof(cli_addr);
client_conn = accept(listen_fd, (struct sockaddr *) &cli_addr, &len);
and you have the client info in cli_addr.sin_addr.s_addr and cli_addr.sin_port.
You can get the pid of the child processing the connection from the return code of fork. That should give you all the information you need to create a table.
For some reason my recvfrom() function for sockets is not blocking on my server code like it is supposed to. I am making a basic UDP server to create a rolling session key system.
What am I doing wrong here? It continues on after this line (before i put the (n < 1)) and was crashing. I am pretty sure recvfrom() is supposed to stop the execution of the program until it gets something from the client...
int sockfd, portNumber;
socklen_t clilen;
char buffer[BUFFER_LENGTH];
struct sockaddr_in serv_addr, from;
int n;
// Invalid arguments
if (argc < 2)
exit(0);
else if (atoi(argv[1]) > 65535 || atoi(argv[1]) < 1)
exit(0);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("Error opening socket.\n");
exit(0);
}
// Taken from reference
bzero((char *) &serv_addr, sizeof(serv_addr));
portNumber = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portNumber);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
printf("ERROR on binding.\n");
close(sockfd);
exit(0);
}
// Get initial session key request
int fromlen = sizeof(struct sockaddr_in);
n = recvfrom(sockfd, buffer, BUFFER_LENGTH, 0, (struct sockaddr *)&from, &fromlen);
if (n < 0)
{
printf("Error in receiving.\n");
exit(1);
}
Thanks
You're trying to use a stream socket for UDP;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
What you mean to do is probably;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
Trying to do recvfrom on an unconnected stream socket will most likely return immediately with an error. Next time, you may want to check errno for a hint.