UNIX Socket FAQ

A forum for questions and answers about network programming on Linux and all other Unix-like systems

You are not logged in.

  • Index
  • » C
  • » Sockets and threads

#1 2009-07-12 11:08 AM

Tommo
Member
Registered: 2007-09-03
Posts: 76

Re: Sockets and threads

Hi.

I am trying to write a client that takes user input and sends it to
the server, while in another thread, we block on recv(), waiting
for messages from the server.  The reason I am doing this, is,
sometimes the server sends the odd spontaneous message to a
client.
I thought about using select(), and adding stdin to the set of fd's.
I am not sure that is what I want though as select() will return as soon
as a key is pressed.
So I thought I might as well try and learn how to program with pthreads.
Here is the gist of my code:

// Here we handle messages from server
void* handle_server_msgs (void* arg)
{
	int nbytes;
	char buf[256];
	// The server's socket
	int s = *((int *) arg);
	
	nbytes = recv (s, buf, sizeof (buf), 0);

	if (nbytes <= 0)
	{
		perror ("recv");
		return NULL;
	}

	buf[nbytes] = '\0';

	// Now do what we want with message...
}

int main (int argc, char* argv[])
{
	pthread_t thread;
	char buf[256];
	int sock;
	size_t len;

	// Set up socket and connect to server here
	sock = socket (PF_INET, SOCK_STREAM, 0);

	//...etc

	// Create new thread to wait for server messages
	pthread_create (&thread, NULL, &handle_server_msgs, &sock);

	// Get Name and send it to the server
	printf ("Enter your name: ");
	get_string (buf, sizeof (buf));
	len = strlen (buf);
	sendall (sock, buf, len);

	// Main loop
	do
	{
		printf ("> ");

		// Store input in buf
		get_string (buf, sizeof (buf));

		len = strlen (buf);

		sendall (sock, buf, len);
	}
	while (strcmp (buf, "quit") != 0);

	close (sock);

	pthread_join (thread, NULL);

	return 0;
}

I am not entirely sure why, but sometimes commands work,
sometimes not.  Mostly not.  I have a feeling it has something
to do with my thread? Am I going about this correctly?

Offline

#2 2009-07-12 04:49 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Sockets and threads

What exactly do you mean by "not work"?  What exactly happens?

I don't see any reason why that approach shouldn't work...  As long as that thread
is the only one reading from the socket, and your main thread is the only one writing
to it...  But, what do you do with the messages you read from the server?  Just print
them out?  Because, if they're supposed to be fixed size or delimited messages or
something, you don't seem to be doing any handling to guarantee you have a complete
(or just one single) message...  And, TCP sure won't do that for you...  It's a simple
byte stream...  Oh, and also, this is a bug:

nbytes = recv (s, buf, sizeof (buf), 0);
...
	buf[nbytes] = '\0';

You can overflow your buffer there, in the case that you receive a full 256-byte
message...  If you need null-termination, you need to pass "sizeof(buf) - 1" to recv()
as the max size to receive...

Offline

#3 2009-07-12 07:24 PM

Tommo
Member
Registered: 2007-09-03
Posts: 76

Re: Sockets and threads

1|name|rating - 'name' is available for playing. He/she has overall rating 'rating'

2|seconds|round - tells us how many seconds are left in 'round' 
(the 2 means thier word is valid)

3|seconds|round - same as above
(the 3 means their word is invalid)

4|anagram|round - sends generated anagram and tells them which round they're on.

5|round|player 1's name|player 1's word|player 2's name|player 2's word - 
end of round information

6|last round|player 1 name|player 1's word|player 1's overall score|player 2|player 2's word|player 2's overall score - end of *last round* information

7 - just means client has finished game and is free to play

8|challenger - 'challenger' has challenged you to a game

Offline

#4 2009-07-12 10:24 PM

Tommo
Member
Registered: 2007-09-03
Posts: 76

Re: Sockets and threads

Like you said Rob, I'm not doing anything after recv().  And that's the problem - recv() seems to be sending more than I want, sometimes I get a bit of the next message. I always forget about this. I'll have to send the message length along with each message so I'll know from the client end (as I've already said).

Offline

#5 2009-07-13 12:08 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Sockets and threads

Offline

#6 2009-07-13 04:35 PM

Tommo
Member
Registered: 2007-09-03
Posts: 76

Re: Sockets and threads

Offline

#7 2009-07-13 10:08 PM

Tommo
Member
Registered: 2007-09-03
Posts: 76

Re: Sockets and threads

#include <stdio.h>
#include <string.h>

int main ()
{
	char string[50] = "The quick brown fox jumped over the lazy dog";
	char *words[10];
	int i, count;

	count = my_strsep (string, words, ' ');
	
	for (i = 0; i <= count; i++)
	{	
		printf ("%s\n", words[i]);
	}

	return 0;
}

int my_strsep(char *string, char *words[], char delim)
{
	char *ptr = string;
	int count = 0;
	size_t len = 0;

	do
	{
		words[count] = ptr;
		ptr = strchr (string + len, delim);

		if (ptr != NULL)
			*ptr = '\0';
		else
			break;

		len += strlen (words[count]) + 1;
		count++;
	}
	while (ptr++ != NULL);

	return count;
}

Offline

#8 2009-07-13 11:45 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Sockets and threads

char **string2tokens (char *str, char delim)
{
    int cnt, i;
    char *p, **toks;

    if (str == NULL) return (NULL);

    for (cnt = 0, p = str; (p = strchr (p, delim)) != NULL; cnt++, p++)
        ;  /* get a delim count */
    cnt++; /* # tokens = delim count + 1 */

    toks = calloc (cnt + 1, sizeof (char*));
    if (toks == NULL) return (NULL);

    for (i = 0, p = str; p && (i < cnt); i++) {
        toks[i] = p;
        p = strchr (p, delim);
        if (p) *p++ = '\0';
    }

    return (toks);
}

Offline

#9 2009-07-14 04:03 PM

Uzume
Administrator
Registered: 2002-08-30
Posts: 186

Re: Sockets and threads

Nice work, Rob (as always).

If you need multiple delimiters (e.g., allow more than one type of delimiter such as a comma or a space, etc.) try replacing strchr() with strpbrk(). If you need to allow multiple delimiters back to back (e.g., allow tokens to be delimited by one or more spaces or tabs, etc.) try alternating the use of strcspn() and strspn().

Of course, it would not be that difficult to just directly use raw character manipulation code to parse your tokens as well (and it might work better than using string functions).

POSIX string functions are very portable and often highly optimized but their interface is not particularly well designed so care needs to be taken in their use.

Offline

#10 2009-08-15 03:18 PM

0788629219
Guest

Re: Sockets and threads

  • Index
  • » C
  • » Sockets and threads

Board footer

Powered by FluxBB