Click here to Skip to main content
15,891,567 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Good evening all. I am working on a poker program, using a TCP client/server. I am having the client do only input/output work, while the server handles all of the operations.
I have run into a problem where I have a card structure that is populated with 5 cards from a deck. I put those 5 cards into 2 arrays, one for the face of the card, the other for the suit. I am them trying to send these arrays to the client to print the hand out for the user. The array gets filled with no problem, but when I send the array to the client, and print it, it prints nothing. There is a lot of code, most of which is messy, so for the time being I will post the code in question, unless you guys need more.

Server:
The definitions used in here are:

C#
1   const char *face[] = { "Ace", "Two", "Three", "Four",
2           "Five", "Six", "Seven", "Eight",
3           "Nine", "Ten", "Jack", "Queen", "King"};
4   const char *suit[] = {"Diamonds", "Hearts", "Clubs", "Spades" };
5
6   const char *handFace[5];
7   const char *handSuit[5];


And the code:
C#
01	n = write(newsockfd,"Here is your hand. Good Luck!",255);
02	             
03	for(v=0;v<5;v++) {
04	    handFace[v] = myDeck.myCards[v].face;
05	    handSuit[v] = myDeck.myCards[v].suit;
06	}
07	                 
08	for(y=0;y<5;y++) {
09	       n = write(newsockfd,&handFace[y],sizeof(handFace[y]));
10	}
11	             
12	for (r=0;r<5;r++) {
13	    n = write(newsockfd,&handSuit[r],sizeof(handSuit[r]));
14	}
15	     
16	for (a=0;a<5;a++) {
17	    printf("%s of %s\n", handFace[a],handSuit[a]);
18	} 


For the client, the definitions are:

C#
1   char *handFace[5];
2   char *handSuit[5];


And the code is:
C#
01	n = read(sockfd,buffer,255);
02	             
03	printf("%s\n",buffer);
04	             
05	for(v=0;v<5;v++) {
06	    n = read(sockfd,&handFace[v],sizeof(handFace[v]));
07	}
08	             
09	for(y=0;y<5;y++) {
10	    n = read(sockfd,&handSuit[y],sizeof(handSuit[y]));
11	}
12	             
13	for(i=0;i<5;i++) {
14	    printf("%s of %s\n", handFace[i],handSuit[i]);
15	} 


It compiles and runs. However in the client, it only prints out " of " as if the array is empty. I am assuming a read or write is wrong, I just don't know where or how.


Ok, I am getting closer. I have my write statements set to
for(v=0; v<5; v++) {
    handFace[v] = myDeck.myCards[v].face;
    handSuit[v] = myDeck.myCards[v].suit;
}
for(y=0;y<5;y++) {
    n = write(newsockfd,handFace[y],sizeof(handFace[y]));
    n = write(newsockfd,handSuit[y],sizeof(handSuit[y]));
}

and my read set to
for(v=0;v<5;v++) {
    n = read(sockfd,buffer1,sizeof(buffer1));
    n = read(sockfd,buffer2,sizeof(buffer2));
    handFace[v] = buffer1;
    handSuit[v] = buffer2;
}
for(i=0;i<5;i++) {
    printf("%s of %s\n", handFace[i],handSuit[i]);
}

It works for the first buffer read. For example if the first face that the server sends in 4, the print loops in the client will only print
4 of
4 of
4 of
4 of
4 of
Can the buffer not be overwritten? - drewd12 3 hrs ago
Posted
Updated 8-Dec-10 11:43am
v3
Comments
drewd12 8-Dec-10 17:49pm    
Did you revise something?

n = write(newsockfd,&handFace[y],sizeof(handFace[y]));

You are sending the pointer to the string and length of a pointer rather than the string itself and its length. Your code should be:
n = write(newsockfd, handFace[y], strlen(handFace[y]));

Same thing with the suit. You could probably simplify your code by just sending a two letter code or index value for each card, and have both sides use the same basic table of suits and faces.
 
Share this answer
 
Comments
drewd12 8-Dec-10 12:26pm    
I replaced sizeof() with strlen() in both the read and write statements, and removed the &, but that gives me a seg fault. Any ideas?
As I said earlier, I think you still misunderstand the difference between a pointer and an array. In your reading code you have the following:
for(v=0; v < 5; v++) {
    n = read(sockfd, buffer1, sizeof(buffer1));
    n = read(sockfd, buffer2, sizeof(buffer2));
    handFace[v] = buffer1;
    handSuit[v] = buffer2;
}

However handFace[] is an array of pointers so as you go through this loop you set handFace[v] to point to buffer1, i.e. the item contains the address of buffer1. So at the end of each loop every element of handFace will point to the same item, which is whatever is in buffer1 at that time. The same holds true for handSuit and buffer2. What your code needs to do is allocate a buffer to each element of the array to hold the item that has just been read in and copy it to the new buffer, something like:
for(v=0; v < 5; v++) {
    n = read(sockfd, buffer1, sizeof(buffer1));
    n = read(sockfd, buffer2, sizeof(buffer2));
    handFace[v] = (char*)malloc(strlen(buffer1) + 1);
    strcpy(handFace[v], buffer1);

    handSuit[v] = (char*)malloc(strlen(buffer2) + 1);
    strcpy(handSuit[v], buffer2);
}

Unfortunately this logic is still flawed, as you cannot be certain of what has been received in either buffer1 or buffer2. What you read from a socket is whatever is pending from your server, which could be any number of cards and suits, or none. So as you read the data from the socket you will need to disassemble it into its constituent parts before storing it in your arrays. The best way to achieve this is to design some message structure that your client and server use for communication, which allows each to identify each card, its value and suit. So perhaps your messages could appear in the form of:
#Five;Hearts#King;Clubs##

Where the '#' identifies the next card with the value and suit seperated by the ';' character. The double '#' character signifies the end of the data.
 
Share this answer
 
The read statements would be the same as well, replacing sizeof with strlen?
 
Share this answer
 
Quote: I replaced sizeof() with strlen() in both the read and write statements, and removed the &, but that gives me a seg fault. Any ideas?

You cannot use uninitialised pointers as destinations for your read statements. You must read into a buffer that is at least long enough to hold whatever message you receive on the socket. Something like:
char buffer[255];
n = read(sockfd, buffer, sizeof(buffer));

Then transfer the input field to its proper location and save a pointer to it in your array.

Using pure C for a program like this is probably not a great idea. If you convert to C++ you will be able to take advantage of the extra features of the Standard Template Library for managing strings, arrays and such like.
 
Share this answer
 
Comments
drewd12 8-Dec-10 14:29pm    
Ok, I am getting closer. I have my write statements set to
[li]
for(v=0;v<5;v++) {
handFace[v] = myDeck.myCards[v].face;
handSuit[v] = myDeck.myCards[v].suit;
}

for(y=0;y<5;y++) {
n = write(newsockfd,handFace[y],sizeof(handFace[y]));
n = write(newsockfd,handSuit[y],sizeof(handSuit[y]));
}
[/li]

and my read set to
[li]
for(v=0;v<5;v++) {
n = read(sockfd,buffer1,sizeof(buffer1));
n = read(sockfd,buffer2,sizeof(buffer2));
handFace[v] = buffer1;
handSuit[v] = buffer2;
}

for(i=0;i<5;i++) {
printf("%s of %s\n", handFace[i],handSuit[i]);
}
[/li]

It works for the first buffer read. For example if the first face that the server sends in 4, the print loops in the client will only print
4 of
4 of
4 of
4 of
4 of

Can the buffer not be overwritten?
OK, I have updated your original question with the latest code you posted. However you still seem to be having a problem with the difference between sizeof() and strlen(). sizeof() is a compile time directive that returns the size of an element or array as declared at compile time; strlen() is a runtime function that returns the actual size of a null terminated string, regardless of the size of the buffer it is contained within. Thus your write statements should be of the form:
n = write(newsockfd, handFace[y], strlen(handFace[y]));

Note the correct use of strlen() to write the actual length of the string rather than sizeof() which returns the length of a pointer.

I also think that the first loop that copies the pointers from myDeck.myCards to handFace as in
handFace[v] = myDeck.myCards[v].face;

is a waste of time; why not write to the socket direct from myDeck.myCards[v].face?

In your read code you read successive items into buffer1 and buffer2 but then point all the items at the same buffer thus losing the first four items you read in. After reading each item you need to copy it to a permanent location before setting the handFace[] or handSuit[] elements to point to it.


Further comments:
You seem to be misunderstanding some of the basics of pointers and arrays and copying items between them; I would suggest going over the relevant section of your C language reference.

You also do not check the result of any of your socket IO calls to see what you are actually writing or reading (how big are your buffers?). Never assume that all function calls are successful, or that they give the results that you expect.

One way of learning exactly what is going on in your program is to use the debugger and step through your code and look at the contents of your variables and arrays to see the results of each step.
 
Share this answer
 
Comments
drewd12 8-Dec-10 18:44pm    
Let me first thank you for everything you have done so far. Your help has been invaluable. I think I am understand the concepts of strlen() vs sizeof(). What I don't quite understand is what you mean when you said I am pointing all items at the same buffer and losing the first four items. The way I have it written, I would think it would read the first face and the first suit into buffer1 and buffer2 respectively, then stick them in the handFace[0] and handSuit[0] so I could access them, and continue to do this for each increment in the loop. Where do I fail this logic?
You have several lines like:
n = write(newsockfd,&handFace[y],sizeof(handFace[y]));


what is sizeof returning, I expect it is always 4 as in char* is 4 bytes. If this is the case you are not going to write the correct number of characters.

Also none of your strings are null terminated which will give you problems printing them.


null terminate
const char *face[] = { "Ace\0", "Two\0" /* etc.*/ }


then get lengths with strlen function e.g.
n = write(newsockfd,&amp;handFace[y],strlen(handFace[y]) + 1);


The + 1 is for the null aswell
 
Share this answer
 
Comments
Richard MacCutchan 8-Dec-10 9:19am    
The strings are automatically null terminated by the compiler. Also the write function should use the pointer to the string not the pointer to the pointer, as I mention above.
ARopo 8-Dec-10 10:25am    
Good point didn't notice that, still what said about sizeof stands

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900