Ok, So Ive been fooling around with pthreads for quite a bit. They seem fairly simple for small programs, but for what im doing its getting a bit complicated and I was hoping someone good enlighten me here.
So the client/server chat seems to be working as usual. Well actually less than usual.
Its not sending any data to any clients at all now. Before it was only sending data to the client that sent it. I.E echoing it back to the original client. That was using fork(). Now that ive used pthreads Im having trouble getting it to echo back to anyone. Its getting the data from clients and running the for loop to send to all clients but its not sending it to any of them its just iterating through and the clients are not receiving anything. The only improvement is that the global variable sockets[][] that holds all address's for clients is being updated globally and accessible to all threads. Whereas with the fork() it was local to each process and could not be updated globaly. So each thread has the list of all clients to send to, its just not happening.
I turned the fork() into a pthread and added a pthread to the client code as well for recv() data.
The parent process, Im guessing is how you would refer to it, in the client reads in data from the user via fgets() and sends it to the server, the thread newThread contains a function that loops a recv() function that receives data from the server. When I say data I mean text messages in a char array. The server parent is constantly listening/accepting connections and when a connection is accepted that connection gets a newThread and its connection (socket) is added to the sockets[][] 2d array. The newThread for the server contains a function called doStuff() that recv() data from the connected sockets and forwards that data to all clients in the sockets[][] array via iteration in the form of a for loop.
Here is the code.
Code in green is not relevant you can skip over that its just setting up the connections.
Code in red is pretty relevant
Code in black is kind of relevant
Server.c
Code:
/* server.c - code for example server program that uses TCP
Jacob Mott*/
#ifndef unix
#define WIN32
#include <windows.h>
#include <winsock.h>
#else
#define closesocket close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netdb.h>
#endif
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#define PROTOPORT 5193 /* default protocol port number */
#define BUFFERSIZE 256
#define QLEN 6 /* size of request queue */
int socketIndex = 0;
void *dostuff(void *socket);
int sockets[BUFFERSIZE][BUFFERSIZE];
/*------------------------------------------------------------------------
* * Program: server
* * port - protocol port number to use
* * Note: The port argument is optional. If no port is specified,
* * the server uses the default given by PROTOPORT.
* *
* *------------------------------------------------------------------------
* */
pthread_mutex_t accept_mutex;
main(argc, argv)
int argc;
char *argv[];
{
struct hostent *ptrh; /* pointer to a host table entry */
struct protoent *ptrp; /* pointer to a protocol table entry */
struct sockaddr_in sad; /* structure to hold server.s address */
struct sockaddr_in cad; /* structure to hold client.s address */
int sd, sd2;
int port; /* protocol port number */
int alen; /* length of address */
pthread_t newThread;
#ifdef WIN32
WSADATA wsaData;
WSAStartup(0x0101, &wsaData);
#endif
memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
sad.sin_family = AF_INET; /* set family to Internet */
sad.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */
/* Check command-line argument for protocol port and extract */
/* port number if one is specified. Otherwise, use the default */
/* port value given by constant PROTOPORT */
if (argc > 1) { /* if argument specified */
port = atoi(argv[1]); /* convert argument to binary */
} else {
port = PROTOPORT; /* use default port number */
}
if (port > 0) /* test for illegal value */
sad.sin_port = htons((u_short)port);
else { /* print error message and exit */
fprintf(stderr,"bad port number %s\n",argv[1]);
exit(1);
}
/* Map TCP transport protocol name to protocol number */
if ( ((int)(ptrp = getprotobyname("tcp"))) == 0) {
fprintf(stderr, "cannot map \"tcp\" to protocol number");
exit(1);
}
/* Create a socket */
sd = socket(PF_INET, SOCK_STREAM, ptrp->p_proto);
if (sd < 0) {
fprintf(stderr, "socket creation failed\n");
exit(1);
}
/* Bind a local address to the socket */
if (bind(sd, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
fprintf(stderr,"bind failed\n");
exit(1);
}
printf("waiting for clients to connect to chat\n");
/* Specify size of request queue */
if (listen(sd, QLEN) < 0) {
fprintf(stderr,"listen failed\n");
exit(1);
}
while(1) {
/* Main server - accept and handle requests */
alen = sizeof(cad);
if ( (sd2=accept(sd, (struct sockaddr *)&cad, &alen)) < 0) {
fprintf(stderr, "accept failed\n");
exit(1);
}
//printf("connection established with client %d\n", cad);
sockets[0][socketIndex] = sd2;
socketIndex++;
pthread_create(&newThread, NULL, dostuff,(void *)&sd2);
}// end accept() loop
return 0;
}// end main
void *dostuff (void *socket){
char file_buffer[10000],f_buffer[1000],name[12], compareTo[1000]="#exit#";
int n, sock;
sock=*(int*)socket;
char buf_recv[1000], buf_send[1000]; /* buffer for string the server sends */
pthread_detach(pthread_self());
printf("connected!\n>");
fflush(stdout);
while(1){
n = recv(sock, buf_recv, sizeof(buf_recv), 0);
fflush(stdout);
buf_recv[n]='\0';
if (strcmp(buf_recv, compareTo) == 0){
//printf("%s, disconnected!\n>", name);
//fflush(stdout);
printf("disconnected!\n>");
fflush(stdout);
exit(0);
}// end if
int i, sk;
for (i = 0; i<BUFFERSIZE; i++){
printf("socets[0][i] = %d\n ", sockets[0][i]);
fflush(stdout);
if ((sk = sockets[0][i]) == 0)
break;
else{
send(sk,buf_recv,strlen(buf_recv),0);
fflush(stdout);
}//end else
}//end for loop
}//end while loop
exit(0);
}// end dostuff()
Client.c
Code:
/* client.c - code for example client program that uses TCP
Jacob Mott*/
#ifndef unix
#define WIN32
#include <windows.h>
#include <winsock.h>
#else
#define closesocket close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#include <stdio.h>
#include <string.h>
#define PROTOPORT 5193 /* default protocol port number */
char localhost[] = "localhost"; /* default host name */
void *sendStuff(void *sock);
/*------------------------------------------------------------------------
* * Program: client
* * Purpose: allocate a socket, connect to a server,
* * Syntax: client [ host [port] ]
* * host - name of a computer on which server is executing
* * port - protocol port number server is using
* * Note: Both arguments are optional. If no host name is specified,
* * the client uses "localhost"; if no protocol port is
* * specified, the client uses the default given by PROTOPORT.
* *------------------------------------------------------------------------
* */
void chat(int);
main(argc, argv)
int argc;
char *argv[];
{
struct hostent *ptrh; /* pointer to a host table entry */
struct protoent *ptrp; /* pointer to a protocol table entry */
struct sockaddr_in sad; /* structure to hold an IP address */
int sd; /* socket descriptor */
int port; /* protocol port number */
char *host; /* pointer to host name */
#ifdef WIN32
WSADATA wsaData;
WSAStartup(0x0101, &wsaData);
#endif
memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
sad.sin_family = AF_INET; /* set family to Internet */
/* Check command-line argument for protocol port and extract */
/* port number if one is specified. Otherwise, use the default */
/* port value given by constant PROTOPORT */
if (argc > 2) { /* if protocol port specified */
port = atoi(argv[2]); /* convert to binary */
} else {
port = PROTOPORT; /* use default port number */
}
if (port > 0) /* test for legal value */
sad.sin_port = htons((u_short)port);
else { /* print error message and exit */
fprintf(stderr,"bad port number %s\n",argv[2]);
exit(1);
}
/* Check host argument and assign host name. */
if (argc > 1) {
host = argv[1]; /* if host argument specified */
} else {
host = localhost;
}
/* Convert host name to equivalent IP address and copy to sad. */
ptrh = gethostbyname(host);
if ( ((char *)ptrh) == NULL ) {
fprintf(stderr,"invalid host: %s\n", host);
exit(1);
}
memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
/* Map TCP transport protocol name to protocol number. */
if ( ((int)(ptrp = getprotobyname("tcp"))) == 0) {
fprintf(stderr, "cannot map \"tcp\" to protocol number");
exit(1);
}
/* Create a socket. */
sd = socket(PF_INET, SOCK_STREAM, ptrp->p_proto);
if (sd < 0) {
fprintf(stderr, "socket creation failed\n");
exit(1);
}
/* Connect the socket to the specified server. */
if (connect(sd, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
fprintf(stderr,"connect failed\n");
exit(1);
}
/* Start chating*/
chat(sd);
return 0;
}
void chat(int sock){
pthread_t newThread;
int n, len; /* number of characters read */
char buf_recv[1000], buf_send[1000], name[15], compareTo[10]="#exit#",compareNull[1000]="\n";/* buffer for data from the server */
printf("connection established with server\n");
pthread_create(&newThread,NULL,sendStuff,(void*)&sock);
while(1){
int gotit=0;
int ah;
while (gotit == 0){
fgets(buf_send, 1000, stdin);
if (strcmp(buf_send, compareNull) == 0){
printf("please enter text don't leave blank\n");
fflush(stdout);
gotit = -1;
}
gotit++;
}
int aa = strlen(buf_send);
buf_send[aa-1]='\0';
send(sock, buf_send,strlen(buf_send),0);
fflush(stdout);
if (strcmp(buf_send, compareTo) == 0)
exit(0);
}//end while loop
}
void *sendStuff(void *sock){
int n, socket;
socket=*(int*)sock;
char buf_recv[1000], name[15];
pthread_detach(pthread_self());
while(1){
if ((n = recv(socket, buf_recv, sizeof(buf_recv), 0)) < 1);
return;
fflush(stdout);
buf_recv[n]='\0';
printf("%s\n",buf_recv);
fflush(stdout);
}
}//end sendstuff()