multi-process in C : global variable's value - c

Here is the code from a website. It used multi-processing to create a server. My question is: will the parent process close(newsockfd) executed before the child process doprocessing(newsockfd) ?
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
void doprocessing (int sock);
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n, pid;
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
/* Now start listening for the clients, here
* process will go in sleep mode and will wait
* for the incoming connection
*/
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
/* Create child process */
pid = fork();
if (pid < 0) {
perror("ERROR on fork");
exit(1);
}
if (pid == 0) {
/* This is the client process */
close(sockfd);
doprocessing(newsockfd);
exit(0);
}
else {
close(newsockfd);
}
} /* end of while */
}
===-=================
void doprocessing (int sock) {
int n;
char buffer[256];
bzero(buffer,256);
n = read(sock,buffer,255);
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
printf("Here is the message: %s\n",buffer);
n = write(sock,"I got your message",18);
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
}
==========-==========================
code is from this website:
http://www.tutorialspoint.com/unix_sockets/socket_server_example.htm

When the process is forked, the gets a copy of the open set of file desriptors, and the reference count on the open filess is incremented accordingly. The close only happens in the parent process, so the child still maintains a reference to the open file. The order of execution doesn't really matter. On a multi-cpu system, it may happen truly simultaneously.
Global variables are not shared by forked child processes. A forked process runs in its own virtual memory space.

Related

How can I change my server so that multiple clients have access the shared data in the server?

Basically, I am doing a tcp project in c and I made it so multiple clients can connect to my server by using fork. In my server I have a linked list structure that keeps data that clients are sending. However, when I am sending data from the client to the linked list located in the server, the server creates a new linked list for that client . Instead of adding all client data to the same linked list. I know for certain its not a problem with the linked list. Fork() duplicates the process, so after calling fork there are actually 2 instances of my program running. So yeah I realized the clients aren't communicating with the same server? How should I fix this problem? Do I get rid of fork? Please conceptually explain to me what I must do. I'm not posting my actual code because it is sensitive . But here is basically what I am doing:
server:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void dostuff(int); /* function prototype */
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen, pid;
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();
if (pid < 0)
error("ERROR on fork");
if (pid == 0) {
close(sockfd);
dostuff(newsockfd);
exit(0);
}
else close(newsockfd);
} /* end of while */
return 0; /* we never get here */
}
void dostuff (int sock)
{
int n;
char buffer[256];
bzero(buffer,256);
n = read(sock,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(sock,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
client :
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.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");
printf("Please enter the message: ");
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);
return 0;
}
Because fork() creates a new process, you will need to use shared memory (shm_open(), shm_unlink(), mmap(),...). You can find based on this other question's answer.
You can get rid of fork and instead
a thread for each connection, which means you can share state between clients in your program. This will however require you to add synchronization (mutexes, etc.) around all shared data.
use a single thread in asynchronous/nonblocking mode (select/epoll/etc.) to serve all clients.

Not receiving full data

I have the following socket code in C. I am trying to receive 70 bytes of data on each cycle. However, I am getting only 4 bytes of data. The full data is something like this (in hex):
4D43475000856308000004B2DE1F04009E00200100000000696CF7AB002F1A00000000
000000325C000402069BFDE70857E22502F41C000036000000DF0B0932100B09DC0719
What is the problem? I have tried to research many StackOverflow answers, but with no help.
The code is as below:
void doprocessing (int sock);
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[1024];
struct sockaddr_in serv_addr, cli_addr;
int n, pid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 14064;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
/* Now start listening for the clients, here
* process will go in sleep mode and will wait
* for the incoming connection
*/
listen(sockfd,5000);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
/* Create child process */
pid = fork();
if (pid < 0) {
perror("ERROR on fork");
exit(1);
}
if (pid == 0) {
/* This is the client process */
close(sockfd);
doprocessing(newsockfd);
exit(0);
}
else {
close(newsockfd);
}
} /* end of while */
}
void doprocessing (int sock)
{
int n,i;
unsigned int *buffer = malloc(1024);
n = read(sock,buffer,1023);
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
printf("Here is the message: %.4x\n",*buffer);
n = write(sock,"MCGP",18);
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
free(buffer);
}
There are quite a number of bugs in your code:
clilen = sizeof(cli_addr); needs to be moved inside of the while loop above the accept() call.
unsigned int *buffer should be unsigned char *buffer instead.
Why are you reading 1023 bytes when you are only expecting 70 bytes?
You need to call read() in a loop until you actually receive all of the bytes you are expecting. read() can return fewer bytes than requested. TCP is a byte stream, it has no concept of message boundaries, the read will return whatever bytes are currently available, so it will return at least 1 byte up to the requested number of bytes.
Your printf() call is only outputting the first 4 bytes of buffer, it is not outputting the full content of buffer. The return value of read() tells you how many bytes were actually received. Loop through the buffer outputting each byte individually.
write(sock,"MCGP",18) is a buffer overflow, since you are only passing 5 bytes (4 characters and the null terminator) but are telling it to send 18 bytes instead.
Try this instead:
void doprocessing (int sock);
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno;
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen;
int pid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR creating socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 14064;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on bind");
exit(1);
}
/* Now start listening for the clients, here
* process will go in sleep mode and will wait
* for the incoming connection
*/
if (listen(sockfd, SOMAXCONN) < 0) {
perror("ERROR on listen");
exit(1);
}
while (1) {
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
/* Create child process */
pid = fork();
if (pid < 0) {
perror("ERROR on fork");
exit(1);
}
if (pid == 0) {
/* This is the client process */
close(sockfd);
doprocessing(newsockfd);
exit(0);
}
else {
close(newsockfd);
}
} /* end of while */
}
void doprocessing (int sock)
{
int n, i;
unsigned char buffer[70], *p = buffer;
size_t len = 70;
do {
n = read(sock, p, len);
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
if (n == 0) {
perror("DISCONNECTED unexpectedly");
exit(1);
}
p += n;
len -= n;
}
while (len > 0);
printf("Here is the message: ");
for (i = 0; i < 70; ++i)
printf("%.02x", buffer[i]);
printf("\n");
n = write(sock, "MCGP", 4);
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
}

threaded server in c

I did not found an answer to my question before, nor did i know if that has an specific name for what i want to do, basically i have a program that runs a simulation, with graphical interface and calculations in the background, and i want to control it through commands with a tcp basic server/client but this means that i have to incorporate the server function inside the controlling function, so i made my server inside a thread and i am running something in the main function, while i call the server function in a thread just for testing, but i cannot send anything to the server, my client application does not get a response, and the server does not receive anything... the code is messy because i am testing a lot of stuff in it, and the identation is messy too...
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
int test= 0;
void threadServer(){
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n, c;
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("ERROR opening socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
{
perror("ERROR on binding");
exit(1);
}
/* Now start listening for the clients, here process will
* go in sleep mode and will wait for the incoming connection
*/
listen(sockfd,5);
clilen = sizeof(cli_addr);
while(c){
/* Accept actual connection from the client */
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr,
&clilen);
if (newsockfd < 0)
{
perror("ERROR on accept");
exit(1);
}
/* If connection is established then start communicating */
bzero(buffer,256);
n = read( newsockfd,buffer,255 );
if (n < 0)
{
perror("ERROR reading from socket");
exit(1);
}
//if(buffer[0]==t){
//c=0;
//exit(1);
//}else{
//c=1;
//}
printf("Here is the message: %s\n",buffer);
/* Write a response to the client */
n = write(newsockfd,"I got your message",18);
if (n < 0)
{
perror("ERROR writing to socket");
exit(1);
}
test =1;
}
//return 0;
}
void main(){
pthread_t threads[1];
int rc;
long t;
char k;
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, threadServer, (void *)t);
if(rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
while(1){
printf("type any key:\n");
scanf("%c",&k);
printf("you typed %c\n", k);
printf("testing server thread : %d\n", test);
}
/* Last thing that main() should do */
pthread_exit(NULL);
}

String with thread in tcp client / server in C

I'm trying to develop an application in C to receive a message and send it in TCP. For that, I'm using a 2 threads : the server thread to listen and a client thread to send it.
Here the server and the main function :
void dostuff(int sock)
{
int n;
char buffer[256];
bzero(buffer,256);
n = read(sock,buffer,255);
if (n < 0) error("ERROR reading from socket");
else {
pthread_t t_tcp_client;
pthread_create(&t_tcp_client, NULL, tcp_client, buffer);
}
n = write(sock,"Message received",18);
if (n < 0) error("ERROR writing to socket");
}
static void *tcp_server(void *p_data)
{
int sockfd, newsockfd, pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(TCP_PORT);
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();
if (pid < 0) error("ERROR on fork");
if (pid == 0) {
close(sockfd);
dostuff(newsockfd);
exit(0);
} else {
close(newsockfd);
}
}
close(sockfd);
return 0;
}
int main (void)
{
pthread_t t_tcp_server;
pthread_create(&t_tcp_server, NULL, tcp_server, NULL);
pthread_join(t_tcp_server, NULL);
return 0;
}
And the client thread :
static void *tcp_client(void *p_data)
{
if (p_data != NULL)
{
char const *message = p_data;
printf("Message transmitted : %s\n", message);
}
return 0;
}
The problem is that the client thread doesn't receive the good char, the result is :
Message transmitted : ???~?
I think the problem comes from the line : n = read(sock,buffer,255); but I don't really understand why.
Thank you for your help
static char buffer[256];
void dostuff(int sock)
{
int n;
bzero(buffer,256);
n = read(sock,buffer,255);
...
}
Be careful when using sockets, one read may don't give you the totality of the message you wait.
In case of structured messages, the protocol you define (you should define it well) have to give a message identifier at first, and you read until you receive sizeof( theSpecificMessage ), theSpecificMessage is identified by the identifier.
do_stuff most likely exited before the client thread did it's work.
The client thread uses stack allocated memory which then had been freed when do_stuff exited, and will be reused by some other code.
A solution to this would be to pass heap allocated memory to the client. If allocated dynamically the latter then needs to be freed by the client after it has done its work.

comparing two strings in c

I have a basic question on strings and char array's in C.
below I have some basic code that compares data coming over a socket(telnet) with an existing string. This however fails. IF I compare a character in the char array it works in[1] == out[1].
Can you advise why the strings don't match and if I am missing something. Do I need to convert the char to anther type of string?
thx
Art
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void dostuff(int); /* function prototype */
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, pid;
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();
if (pid < 0)
error("ERROR on fork");
if (pid == 0) {
close(sockfd);
dostuff(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[2];
char kjh[] = "aaa";
bzero(buffer,256);
n = read(sock,buffer,255);
if (n < 0) error("ERROR reading from socket");
if (strcmp(ptr,kjh) == 0)
{
printf("they are the same: %s.\n",buffer);
do_other_stuff();
}
printf("Here is the message!: %s\n",buffer);
n = write(sock,"I got your message",19);
if (n < 0) error("ERROR writing to socket");
}
void do_other_stuff()
{
printf("function works:");
}
For a start the buffer is only 2 characters long, but the read(sock, buffer, 255) tries to read a lot more than that. In addition you need to add the null character at the end of the string before doing strcmp
the only thing that can make this code to work is to have good basic knowledge, you are committing silly mistakes here, be observant and anticipate the areas where you probably will get lazy, like in pointers and string operations. Will help you in long run.

Resources