Thread-specific data - c

I have a client program as follows and I need to make it multithreaded i.e one thread per connection. But the variable sockfd is to be kept global to one thread. I understand to do this I need to use pthread_key_t, pthread_key_create...etc. But, I am confused how to use it. I would be gratefull for any help.
int sockfd;
pthread_key_t key_to_sockfd;
void error(const char *msg)
{
perror(msg);
exit(0);
}
void set_connection(char *argv[])
{
int portno;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
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");
return;
}
void send_message()
{
char buffer[256];
int i=0,n;
do{
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");
i++;
}while(i<3);
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
return;
}
void disconnect()
{
close(sockfd);
return;
}
void client_thrd(char *argv[])
{
set_connection(argv);
send_message();
disconnect();
}
int main(int argc, char *argv[])
{
pthread_t thid[2];
int i;
void *status;
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
for(i=0;i<1;i++)
pthread_create(&thid[i],NULL,(void*)&client_thrd,(void*)argv);
for(i=0;i<1;i++)
pthread_join(thid[i],&status);
return 0;
}
I have executed the program for one thread and works fine. But as I increase the number of threads to more then one ofcourse it does not work because of the global vaiable sockfd. This is a test program for something much larger.
Thanks and Regards

It is very easy to use. You call pthread_key_create(&key_to_sockfd, NULL) at the start of your program then in each thread you will see an initial value of NULL. Use the function pthread_setspecific(key_to_sockfd, <pointer to a struct which contains sockfd>) in each thread.
From then on each thread will see a different pointer to the structure that contains your sockfd. When your thread is done with it, you delete the structure and use pthread_setspecific(key_to_sockfd, NULL)
When the threads are finished you call pthread_key_delete(key_to_sockfd) to remove the storage. You can also automatically cleanup by providing a callback function to pthread_key_create to free up the memory when the thread has finished.

From what I see you don't need a global variable to achieve what you want to do. Create a "state" data structure and initialize it for each thread before launching it. The void* parameter in the thread interface is made for this.

If I look to your code you overwrite with each thread you start the socket descriptor sockfd. So each thread will make a new connection and gets a new sockfd. With this code you have the good possibility one thread is closing the connection of another thread. If you want to use for each thread its own socket descriptor why don't you use a pointer to share the same socket descriptor within the same thread?
void client_thrd(char *argv[])
{
int sockfd;
set_connection(&sockfd, argv);
send_message(&sockfd);
disconnect(&sockfd);
}

Related

Static variable in C

I have this program that is a part of a server with tcp protocol, that gets a number from the client and uses it in another function.
Also I have a static int type variable that i want to count each time the server gets a message from a client, but each time it does not keep its value;
The variable is counter
Can you guys tell me why this is happening?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// used port
#define PORT 1114
// error code
extern int errno;
static int counter;
int main ()
{
struct sockaddr_in server; // structure used by server
struct sockaddr_in from;
char message[100]; //message received from client
int socketDescriptor; //socket descriptor
//creating socket
if ((socketDescriptor = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("[server]Error at socket\n");
return errno;
}
//preparing data structures
bzero (&server, sizeof (server));
bzero (&from, sizeof (from));
//filling structures
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (PORT);
//attach socket to descriptor
if (bind (socketDescriptor, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
perror ("[server]Error at bind\n");
return errno;
}
//server is listening
if (listen (socketDescriptor, 2) == -1)
{
perror ("[server]Error at listen\n");
return errno;
}
/serving concurrent the clients
while (1)
{
int client;
int length = sizeof (from);
printf ("[server]Waiting at port %d...\n",PORT);
fflush (stdout);
//accepting client
client = accept (socketDescriptor, (struct sockaddr *) &from, &length);
counter ++;
switch(fork())
{
case -1:
perror("fork err\n");
exit(2);
case 0:
//error if failed connection
if (client < 0)
{
perror ("[server]Error at accept\n");
continue;
}
//conenction established
bzero (message, 100);
printf ("[server]Waiting for message...\n");
fflush (stdout);
//reading message
if (read (client, message, 100) <= 0)
{
perror ("[server]Error at read\n");
close (client); //closing connection
continue; //keep listening
}
printf ("[server]Message was received%s\n", message);
//this is where I want to increment counter, when I want to verify message
int number;
number = atoi(message);//convert char to int
printf("The number is: %d\n", number);//print number
printf("The counter is : %d\n", counter);
fflush(stdout);
exit(2);
}
close (client);
} /* while */
} /* main */
Just move counter++ to the parent process. When the child process starts it gets a copy of counter and the one you modify does not affect it's copy (original actually) in the parent process. If you update it in the parent process you will achieve what you want.
int main(int argc, char ** argv)
{
int number;
int listenfd, connfd, n;
pid_t childpid;
socklen_t clilen;
char message[MAXLINE], answer[MAXLINE];
struct sockaddr_in clientaddr, serveraddr;
int counter;
counter = 0;
// create socket
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("ERROR at creating socket\n");
exit(2);
}
// preparation of socket address
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(PORT);
// bind the socket
bind(listenfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr));
// listen to the socket
listen(listenfd, LIMIT);
printf("Server running, waiting for connections at port : %d\n", PORT);
while (1)
{
clilen = sizeof(clientaddr);
// accept a connection
connfd = accept(listenfd, (struct sockaddr *) &clientaddr, &clilen);
printf("Recieved guest\n");
switch (fork())
{
case -1:
perror("fork err\n");
exit(2);
case 0:
/* eroare la acceptarea conexiunii de la un client */
if (connfd < 0)
{
perror("[server]Eroare la accept().\n");
continue;
}
/* s-a realizat conexiunea, se astepta mesajul */
bzero(message, 100);
printf("[server]Asteptam mesajul...\n");
fflush(stdout);
/* citirea mesajului */
if (read(connfd, message, 100) <= 0)
{
perror("[server]Eroare la read() de la client.\n");
close(connfd); /* inchidem conexiunea cu clientul */
continue; /* continuam sa ascultam */
}
printf ("[server]Message was received...%s\n", message);
fflush(stdout);
number = atoi(message);
printf("The number is: %d\n", number);
printf ("%d\n", counter + 1);
_exit(0); // The child should not create further grand children
default:
counter++;
break;
}//switch
}//for
close(connfd);
}//main
You appear to be forking before setting the counter. Since forking duplicates the entire process, the copy of counter in each child process is different from the parent.
Sharing variables between applications in C can be tricky, but actually there's a pretty easy fix for your case and it will improve performance too. If you look at your code, you're forking after the connect and then handling, in the child, the possibiliy that the connfd < 0. If you handled that in the parent process, the counter could belong to the parent and could be incremented before the fork.
A few other notes here come to mind. Remember, fork duplicates the parent process, so the children in your case are still within a while(1) loop. When you continue you loop back to the next iteration of the while(1) loop, but this doesn't seem correct; you want the child process to exit when it's done handling the connection. This also means as you accept connections, you fork but the fork never dies - I guess that's more a "process leak" than a memory leak, but will certainly eat up memory. Finally, just to throw it out there, forking to handle each request is probably the slowest way to concurrently handle connections. I've had great success with pthread in this case. Since threads share a process space, the threads can even persist and handle many connections before dying ( put the connections on a queue and have the threads poll it, for example ) becasuse they can continue to share connections with their "parent" ( though it's really a sibling thread in this case).

multi-process in C : global variable's value

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.

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);
}

Socket multithreading Implementation C

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.

full duplex communication between server & client

I want to make a code for full duplex communication between server & client using this code.
I got error in receive-message thread from server side & in send-message thread from client side.
please help me to solve this errors & suggest me if any other changes are required.
Thanks :)
server.cpp
int newsockfd, n;
void error(const char *msg)
{
perror(msg);
exit(1);
}
void* recvFn( void* data )
{
char buffer[256];
while(n==0){
memset( buffer, sizeof(buffer), 0);
n = recv(newsockfd,buffer,255,MSG_PEEK);
if(n>0){
printf("cliet: ");
printf("%s",buffer);
}
}
return NULL;
}
void* sendFn( void* data )
{
char temp[255], buffer[255];
while(n==0){
memset( buffer, sizeof(buffer), 0);
fgets(temp,255,stdin);
sprintf(buffer,"clent: %s",temp);
n = send(newsockfd,buffer,strlen(buffer),MSG_EOR);
}
return NULL;
}
int main(int argc, char *argv[])
{
int sockfd, portno;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
pthread_t recvThread, sendThread;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
memset( &serv_addr, sizeof(serv_addr), 0);
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
int on = 1;
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof( on ) ) != 0 ) {
close( sockfd );
return -1;
}
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");
n = 0;
int rc;
rc = pthread_create( &recvThread, NULL, recvFn, NULL);
if(rc){
printf("error in receive-message thread\n");
return -1;
}
rc = pthread_create( &sendThread, NULL, sendFn, NULL);
if(rc){
printf("error in send-message thread\n");
return -1;
}
close(newsockfd);
close(sockfd);
pthread_cancel(recvThread);
pthread_cancel(sendThread);
return 0;
}
client.cpp
int sockfd, n;
void* recvFn( void* data )
{
char buffer[255];
while( n==0 ){
memset( buffer, sizeof(buffer), 0);
n = recv(sockfd,buffer,255,MSG_PEEK);
if(n>0){
printf("server: ");
printf("%s",buffer);
}
}
return NULL;
}
void* sendFn( void* data )
{
char temp[255], buffer[255];
while( n==0 ){
memset( buffer, sizeof(buffer), 0);
fgets(temp,255,stdin);
sprintf(buffer,"clent: %s",temp);
n = send(sockfd,buffer,strlen(buffer),MSG_EOR);
}
return NULL;
}
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int portno;
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);
}
pthread_t recvThread, sendThread;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
portno = atoi(argv[2]);
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
memset( &serv_addr, sizeof(serv_addr), 0);
serv_addr.sin_family = AF_INET;
memcpy((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 on connecting");
n = 0;
int rc;
rc = pthread_create( &sendThread, NULL, sendFn, NULL);
if(rc){
printf("error in send-message thread\n");
return -1;
}
rc = pthread_create( &recvThread, NULL, recvFn, NULL);
if(rc){
printf("error in receive-message thread\n");
return -1;
}
close(sockfd);
pthread_cancel(recvThread);
pthread_cancel(sendThread);
return 0;
}
Your pthread_mutex operations are completely pointless. You're referring only to local variables inside the mutex lock other than n, which should be local in each thread and newsockfd which also should not be global, see below. (Don't you think that a function which calls recv should have a local variable to capture the number of bytes read, and not share that silly little temporary variable globally with other threads?)
Your main thread is in a while loop, creating threads like crazy. Also, inside that loop it has closed the one and only accepted socket, right after creating the threads.
You forgot to put your accept inside the loop, evidently.
Also you seem to think that the main loop will somehow wait for the pair of threads to terminate before launching new ones. You are missing pthread_join calls to wait for the threads finish communicating. If you want the thread to keep going while the main loop accepts new connections using new threads, you should make those threads detached with pthread_detached or using a thread-creation attribute which makes them detached. Non-detached threads which are not pthread_join-ed continue to occupy resources.
Speaking of shutdown, is it really the correct condition that the threads keep looping while n == 0? As soon as n is set to nonzero by one of the threads, the shutdown condition is met. But a nonzero value is normal: some bytes written or read. Your reader should terminate the loop when there is a fatal receive error on the socket, or the read returns zero.
Also, you are evaluating n == 0 outside of the mutex!
If you want to accept multiple concurrent connections, each with its pair of threads, then you cannot use a single global socket. You have to give each pair of threads their own socket. The two threads within each pair do not have to use a mutex to share the socket. The socket calls are thread-safe in the kernel and the threads are not both doing reads or writes; one is reading and one is writing.
Other problems
Your sender keeps sending uninitialized garbage: a buffer that was never set to contain any data.
You have a bzero of 256 bytes on an array of 255 bytes.
Also
Don't use bzero (or bcopy, etc). It's a BSD-ism from the 1980's. The C language was finally standardized in 1989 by ANSI and soon after in 1990 by ISO. At that time, it already had the library functions memset, memcpy and memmove.
I think 22 years later, it is safe to retire bcopy, dontcha think?

Resources