I have a simple socket server here, and have what seems to me should be a simple question. Before the socket accepts connections I wish to have it print its process id. But it won't print anything no matter what it is, until there has been a connection. At first I thought this was because the accept call was blocking the print somehow so I tried adding this in various places:
int fdflags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, fdflags | O_NONBLOCK);
But this had no effect on the code other than making the accept non blocking. So I was hoping someone here might be able to tell me what is going on. The server otherwise works. I'll go ahead and post the client code too.
server.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
static void error(char *msg) {
perror(msg);
exit(1);
}
static void SIGCHLD_Handler(int sig) {
waitpid(-1, NULL, WNOHANG);
}
int main(int argc, char *argv[]) {
int num,sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
struct sigaction sigact;
sigact.sa_handler = SIGCHLD_Handler;
if (sigaction(SIGCHLD, &sigact, 0)) error("sighandle def");
int n, childPid;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
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("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
printf("I am the Knock Knock server and my pid number is %d\n", getpid());
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) else error("ERROR on accept");
bzero(buffer,256);
childPid = fork();
if (childPid < 0) error ("ERROR on fork");
else if (childPid == 0) {
close(sockfd);
while(1) {
// read an int from the client that says how big the message will be
n = read(newsockfd, &num, sizeof(int));
// if client sends just Enter, then quit
if(num==2) break;
// read num bytes from client
n = read(newsockfd,buffer,num);
if (n < 0) error("ERROR reading from socket");
// display the message from the client
printf("Here is the message: %s\n",buffer);
num=19;
// Tell the client to expect 19 bytes
n = write(newsockfd, &num, sizeof(int));
// Send client 19 bytes
n = write(newsockfd,"I got your message",num);
if (n < 0) error("ERROR writing to socket");
}
exit(0);
} else close(newsockfd);
}
return 0;
}
client.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
void error(char *msg) {
perror(msg);
exit(0);
}
int main(int argc, char *argv[]) {
int num, 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");
do{
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
num = strlen(buffer)+1;
// send server an int that says how long the coming message will be
n = write(sockfd, &num, sizeof(int));
// num=2 when user just presses Enter. No message = quit
if(num==2) break;
// send server the message (num bytes long)
n = write(sockfd,buffer,num);
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
// read how many bytes are coming from the server
n = read(sockfd, &num, sizeof(int));
// read num bytes from the server
n = read(sockfd,buffer,num);
if (n < 0)
error("ERROR reading from socket");
// display the message from the server
printf("%s\n",buffer);
}while(1);
return 0;
}
Add a call to fflush(stdout); after the call to printf, or use setvbuf(stdout, NULL, _IOLBF, 0); to set stdout to line-buffered.
Did you try some:
pid_t pid = getpid();
and try to use gdb to print pid value?
Nevertheless, your pid should print. What if you try :
printf("pid = %ld\n", getpid());
accept() blocks, but it doesn't interfere with printf(), and making it non-blocking won't help that, and will destroy the correct working of your program unless you really know what you're doing with non-blocking network code. This must be a buffering problem: fflush(stout) should fix it.
Related
I have two programs, one acting as a server and one acting as a client. They are supposed to act like you are connecting to remote system using ssh. The client sends a command and the server executes the command and prints the output to the server. Although my code does exactly that, there is a delay on the output after the first command. For example if the client sents date, the server will return the date. If the client sends date again it will print message was received but not the output. On the third input from client, the second date will be executed and print on the client Here is the message:date and so on. Any ideas would be really apreciated.
Server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MAX_PINS 1
void error(const char *msg){
perror(msg);
exit(1);
}
void exec_comm(int sock,int nerror,char buff[]){
dup2(sock,1);
dup2(nerror,2);
if(system(buff)==-1){
printf("command not found\n");
}
}
int main(int argc, char *argv[]){
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
char buffer[256];
char* comm[20],*cbuff;
struct sockaddr_in serv_addr, cli_addr;
int n,i,done=0,correct=0;
char str[INET_ADDRSTRLEN];
char* args,*pins[MAX_PINS]={"1234"},pin[10];
FILE* fd;
int nerror;
if (argc < 2){
fprintf(stderr, "No port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
memset((char *) &serv_addr, 0, 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("ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
if (inet_ntop(AF_INET, &cli_addr.sin_addr, str, INET_ADDRSTRLEN) == NULL) {
fprintf(stderr, "Could not convert byte to address\n");
exit(1);
}
fprintf(stdout, "The client address is :%s\n", str);
while(1){
bzero(buffer, 256);
n = read(newsockfd, buffer, 255);
sscanf(buffer,"%s\n",buffer);
printf("The message that was read was:\t%s\n",buffer);
if (n < 0) error("ERROR reading from socket");
fprintf(fd,"%s\n",buffer);
if(strcmp(buffer,"exit\n")==0||strcmp(buffer,"exit")==0){
printf("Exiting...\n");
done=1;
break;
}
exec_comm(newsockfd,nerror,buffer);
printf("Here is the message: %s\n", buffer);
n = write(newsockfd, "message received", 17);
if (n < 0) error("ERROR writing to socket");
}
fclose(fd);
close(newsockfd);
close(sockfd);
return 0;
}
Client:
#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");
n = write(sockfd, stdin, sizeof(int));
if (n < 0)
error("ERROR writing to socket");
do{
printf("Please enter the message: ");
bzero(buffer, 256);
fgets(buffer, 255, stdin);
if(strcmp(buffer,"exit\n")==0||strcmp(buffer,"exit")==0){
printf("Exiting...\n");
n = write(sockfd, buffer, strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
close(sockfd);
break;
}
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);
}while(1);
return 0;
}
n = write(sockfd, buffer, strlen(buffer));
That's your problem right here. Calls to write do not result in individual distinguishable messages, one message per call. They result in a single homogenous stream (that's the "stream" in SOCK_STREAM) of bytes with no delimiters.
You have newlines that separate commands, which is nice and all, but read has no idea about newlines. It will just wait until the buffer is full, or enough time has passed, or whatever. You have no control over it.
You basically have 2 ways to fix this.
Read character by character (pass the length of 1) and stop as soon as you see a newline. Accumulate the characters in a buffer, then execute it.
Send the length of each message before the message itself, in a fixed-length record, so that the server can safely read the length and then use it to read the message itself.
I want to write a TCP server-client chat, but when I start the two threads for reading from and writing to a socket at both sides, I think they block each other out. Can anyone help me with this?
Server Code:
/* A simple server in the internet domain using TCP the port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
struct server_args_runner{
char buffer [256];
int newsockfd;
pthread_t tid;
pthread_attr_t attr;
//read/write attribute (read == 0 and write == 1)
int rw;
};
void error(char *msg){
perror(msg);
exit(1);
}
void* server_runner_fun(void* args){
// this is the chat part!
// get args:
int n;
struct server_args_runner *sar = (struct server_args_runner*) args;
if(sar->rw == 0){
printf("server thread trys to read from socket...\n");
//read-part
while(1){
bzero(sar->buffer, 256);
n = read(sar->newsockfd, sar->buffer, 255);
if (n < 0){
error("ERROR reading from socket");
}
}
printf("%s\n", sar->buffer);
} else {
printf("server thread trys to write to socket...\n");
//write-part
while(1){
bzero(sar->buffer, 256);
fgets(sar->buffer, 255, stdin);
n = write(sar->newsockfd, sar->buffer, strlen((char *) &(sar->buffer)));
if (n < 0){
error("ERROR writing to socket");
}
}
}
}
int main(int argc, char *argv[]){
//fd = filedescriptor
int sockfd, portno, clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2){
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
//socket(...) returns a descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1){
error("ERROR opening socket");
}
printf("Socket created successfully.\n");
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;
//htons(..) converts the short from hostbyteorder to networkbyteorder
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) == -1){
error("ERROR on binding");
}
printf("binding successfull on port %d\n", portno);
listen(sockfd, 2);
clilen = sizeof(cli_addr);
printf("server is listening ...\n");
struct server_args_runner server_write_t, server_read_t;
server_write_t.newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
printf("server accepted connection to client.\n");
if (server_write_t.newsockfd < 0){
error("ERROR on accept");
}
//initializing both server_threads
pthread_attr_init(&server_write_t.attr);
pthread_attr_init(&server_read_t.attr);
server_write_t.rw = 1;
server_read_t.rw = 0;
bcopy(&server_write_t.newsockfd, &server_read_t.newsockfd, sizeof(server_write_t.newsockfd));
pthread_create(&server_write_t.tid, &server_write_t.attr, server_runner_fun, &server_write_t);
pthread_create(&server_read_t.tid, &server_read_t.attr, server_runner_fun, &server_read_t);
pthread_join(server_write_t.tid, NULL);
pthread_join(server_read_t.tid, NULL);
return 0;
}
Client code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
struct client_args_runner{
char buffer [256];
int sockfd;
pthread_t tid;
pthread_attr_t attr;
//read/write attribute (read == 0 and write == 1)
int rw;
};
void error(char *msg){
perror(msg);
exit(0);
}
void* client_runner_fun(void* args){
// this is the chat part!
// get args:
int n;
struct client_args_runner *car = (struct client_args_runner*) args;
if(car->rw == 0){
printf("client thread trys to read from socket...\n");
//read-part
while(1){
bzero(car->buffer, 256);
n = read(car->sockfd, car->buffer, 255);
if (n < 0){
error("ERROR reading from socket");
}
}
printf("%s\n", car->buffer);
} else {
printf("client thread trys to write to socket...\n");
//write-part
while(1){
bzero(car->buffer, 256);
fgets(car->buffer, 255, stdin);
n = write(car->sockfd, car->buffer, strlen((char *) &(car->buffer)));
if (n < 0){
error("ERROR writing to socket");
}
}
}
}
int main(int argc, char *argv[]){
int portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
if (argc < 3){
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
struct client_args_runner client_write_t, client_read_t;
client_write_t.sockfd = socket(AF_INET, SOCK_STREAM, 0);
bcopy(&client_write_t.sockfd, &client_read_t.sockfd,
sizeof(client_write_t.sockfd));
if (client_write_t.sockfd == -1){
error("ERROR on creating socket_file_descriptor");
}
printf("socket created successfully.\n");
server = gethostbyname(argv[1]);
printf("hostname is valid.\n");
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);
printf("before connecting to client..\n");
if (connect(client_write_t.sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) == -1){
error("ERROR connecting");
}
printf("client connected successfully to server.\n");
//initializing both client_threads
pthread_attr_init(&client_write_t.attr);
pthread_attr_init(&client_read_t.attr);
client_write_t.rw = 1;
client_read_t.rw = 0;
pthread_create(&client_write_t.tid, &client_write_t.attr, client_runner_fun, &client_write_t);
pthread_create(&client_read_t.tid, &client_read_t.attr, client_runner_fun, &client_read_t);
pthread_join(client_write_t.tid, NULL);
pthread_join(client_read_t.tid, NULL);
return 0;
}
Your printfs in both the client and server readers are outside the while(1) loops, so your client and server are communicating fine, you just aren't printing anything you read from the sockets.
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
char *result1 = "Ian G. Harris";
char *result2 = "Joe Smith";
char *result3 = "Jane Smith";
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
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("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
printf("Address server started\n");
while (strcmp(buffer, "+++\n") != 0)
{
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
if (strcmp(buffer, "harris#ics.uci.edu\n") == 0)
{
printf("%s\n", result1);
n = write(newsockfd,"harris#ics.uci.edu",18);
if (n < 0) error("ERROR writing to socket");
}
else if(strcmp(buffer, "joe#cnn.com\n") == 0)
{
printf("%s\n", result2);
n = write(newsockfd,"joe#cnn.com",18);
if (n < 0) error("ERROR writing to socket");
}
else if(strcmp(buffer, "jane#slashdot.org\n")==0)
{
printf("%s\n", result3);
n = write(newsockfd,"jane#slashdot.org",18);
if (n < 0) error("ERROR writing to socket");
}
}
return 0;
}
client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(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");
while (strcmp(buffer, "+++\n") != 0)
{
printf("> ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
if (strcmp(buffer, "+++\n") == 0)
{
exit(0);
}
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
}
return 0;
}
I wrote a server.c and a client.c and I need to make some changes to my server.c so that it never quits until I press ctrl-c. I put the client part just in case.
below is the correct format:
client
> harris#ics.uci.edu
Ian G. Harris
> joe#cnn.com
Joe Smith
>
server
Address server started
harris#ics.uci.edu
joe#cnn.com
the only problem I have here is that when I type "+++" in the client, both the client and server quit. The client should quit but the server should wait for another client and continue responding to requests and printing the associated email addresses until its process is killed externally by typing ctrl-c.
Can someone tell me how to fix it? specific examples would be better. Thanks in advance.
Try loop with accept:
while(true)
{
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
printf("Accepted new connection\n");
while (strcmp(buffer, "+++\n") != 0) { ... }
}
Please note that this cannot handle simultaneous connections, you need to use asynchronous IO for that which is more complex.
I am trying to write a server that can handle at most 5 concurrent clients.
Whenever a client gets successfully connected to the server & the number of clients is less than or equal to 5, the server sends a welcome message, generates a 5 digit unique random number for identifying that client, sends this number to the client and prints this number in the console.If the number of clients tends to be greater than 5, then for each new request, it just sends a message "Connection Limit Exceeded" to the client & closes the connection.
Client just prints the messages sent by the server.
The problem I'm facing is that, the random number is not being propagated properly to the client.Few times the client prints the same number as generated by the server but few times the client just prints 0(as the variable storing incoming value of that random number is initialized to 0).
What could be the reason behind this?
Here are the codes for client and server:
server:
/* A simple server in the internet domain using TCP
The port number is passed as an argument
This version runs forever, forking off a separate
process for each connection
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <stdlib.h>
void dostuff(int); /* function prototype */
void write_once (int sock);
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, pid, count = 0;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
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("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
pid = fork();
count++;
if (pid < 0)
error("ERROR on fork");
if (pid == 0 && count <=5 ) {
close(sockfd);
dostuff(newsockfd);
exit(0);
}
if (pid == 0 && count >= 5 ) {
close(sockfd);
write_once(newsockfd);
exit(0);
}
else close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
/******** DOSTUFF() *********************
There is a separate instance of this function
for each connection. It handles all communication
once a connnection has been established.
*****************************************/
void dostuff (int sock)
{
int n;
char buffer[256];
bzero(buffer,256);
n = write(sock,"Welcome\n",8);
if (n < 0) error("ERROR writing to socket");
srand((unsigned int)time(NULL));
int r = rand() % 90000 + 10000;
int converted_r = htonl(r);
n = write(sock, &converted_r, sizeof(converted_r));
if (n < 0) error("ERROR writing to socket");
printf("%d\n", r);
}
void write_once (int sock)
{
int n;
char buffer[256];
bzero(buffer,256);
n = write(sock,"Connection Limit Exceeded!!",28);
if (n < 0) error("ERROR writing to socket");
}
client:
#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;
int received_int = 0;
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");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
n = read(sockfd, &received_int, sizeof(received_int));
if (n < 0)
error("ERROR reading from socket");
printf("%d\n", ntohl(received_int));
close(sockfd);
return 0;
}
Reference
The issue is that TCP is a stream oriented protocol, and not packet oriented. So it may happen that
The first read() of the client reads what the first write() of the server sent ("Welcome")
The second read() of the client reads what the second write() of the server sent (Your number)
This is what you expect and what sometimes happens.
However, it might also be that the client reads the data of both writes of the server at once! This usually happens when
either the server aggregated the two writes to a single tcp-packet
or the client reads the data after both tcp segments with data arrived
You cannot make sure what happens and cannot rely on any specific behaviour.
How to fix this depends solely on your protocol. If the first message is always "Welcome\n", then try to read only 8 bytes first. If you happen to read n < 8 bytes, you have to retry and read 8-n bytes to get the rest of the message. Subsequently read sizeof(received_int) bytes, also watching for the real number of bytes received.
If the message is of variable length you will have to use some kind of framing like a preceding length-byte or something like that.
I am working on a implementing a multithread multi client single server socket in C. However for whatever reason currently the program, when using pthread_create() to create a new thread, it does not advance past that line of code. I have put print lines before and after this line of code and all of the print lines before hand print fine but none of them after print. This leads me to believe that pthread_create() is somehow buggy. The strange thing about this is I can have 1 client connect and successfully sent/receive data from the server but because the loop that the listen() command is in is not advancing I cannot take on additional clients. I appreciate your help in this matter.
Server Code
#include <stdio.h>
#include <stdlib.h> //for IOs
#include <string.h>
#include <unistd.h>
#include <sys/types.h> //for system calls
#include <sys/socket.h> //for sockets
#include <netinet/in.h> //for internet
#include <pthread.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
void *threadFunc(int mySockFd)
{
int n;
char buffer[256];
do
{
bzero(buffer,256);
n = read(mySockFd,buffer,255);
if (n < 0)
{
error("ERROR reading from socket");
}
else if(strcmp(buffer, "EXIT\n") == 0)
{
printf("Exit by user\n");
pthread_exit(NULL);
}
else
{
printf("Here is the message: %s\n",buffer);
n = write(mySockFd,"I got your message",18);
if (n < 0)
{
error("ERROR writing to socket");
}
}
}while(n >= 0);
}
int main(int argc, char *argv[])
{
int sockfd;
int newsockfd;
int portno;
pthread_t pth;
int n; /*n is the return value for the read() and write() calls; i.e. it contains the number of characters read or written.*/
int i = 0;
printf("after var decl");
socklen_t clilen; /*clilen stores the size of the address of the client. This is needed for the accept system call.*/
char buffer[256]; /*The server reads characters from the socket connection into this buffer.*/
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
if (argc < 2)
{
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error("ERROR opening socket");
}
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("ERROR on binding");
}
do
{
printf("before listen");
listen(sockfd,5);
printf("after listen");
clilen = sizeof(cli_addr);
printf("before accept");
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen);
printf("after accept");
pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i);
printf("after pthread create");
if (newsockfd < 0)
{
error("ERROR on accept");
}
}while(1 == 1);
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0)
{
error("ERROR reading from socket");
}
printf("Here is the message: %s\n",buffer);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
and here is the Client 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> /*The file netdb.h defines the structure hostent, which will be used below.*/
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd;
int portno;
int 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");
}
do
{
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if(strcmp(buffer,"EXIT\n") == 0)
{
printf("Connection Terminated\n");
break;
}
if (n < 0)
{
error("ERROR writing to socket");
}
bzero(buffer,256);
n = read(sockfd,buffer,255);
printf("%s\n",buffer);
if (n < 0)
{
error("ERROR reading from socket");
printf("%s\n",buffer);
}
}while(1 == 1);
close(sockfd);
return 0;
}
Two errors:
You are casting too much, the only place here should be the inaddr stuff.
You are not listening to your compiler, crank up the warning level.
Now, the problem (or maybe just one?) is actually this:
pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i);
This will call threadFunc(newsockfd) and pass the result to pthread_create. The second part will never happen though, because that function calls pthread_exit or falls off the end without returning anything, which could cause anything to happen.
Your server code isn't displaying the printf statements reliably is because you didn't end the strings passed to printf with a "\n".
Change all of your printf statements to include a trailing \n such that output will be "flushed" immediately. E.g.
Instead of:
printf("after pthread create");
Do this:
printf("after pthread create\n");
Repeat that fix for all of your printf statements. And then the program flow will be more readily visible as clients connect to it.
There's probably about 5 or 6 other bugs in your code. The main one that I want to call out is just because the client sent 4 bytes of "EXIT", doesn't mean the TCP stream won't fragment that into "EX" and "IT" across two seperate read calls depending on the state of the intertubes. Always write your protocol code as if read/recv were only going to return one char at a time. OR just use MSG_WAITALL with recv() so that you always read the chunk size.