Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > socket programming in C issue

socket programming in C issue
Thread Tools
Mac Enthusiast
Join Date: Sep 2000
Location: France
Status: Offline
Reply With Quote
Aug 3, 2002, 06:34 AM
 
Hi everyone
I just happened to learn a few things about network programming in C, but I ran across some issues in my own programs I hope you can solve.
What I'm trying to do is pretty simple : I just want to program a client program connecting to a server program on a predefined port, and sending a multiline message all at once to a server when the user enters the line "." (like the mail tool I think)
So here's the server code :
Code:
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/time.h> #include <sys/types.h> #include <string.h> #include <unistd.h> #define MYPORT 3490 #define BACKLOG 10 /* Max queued connections */ #define MAX 1000 /* buffer max char */ main() { struct sockaddr_in my_addr; struct sockaddr_in their_addr; int listener_fd, new_fd; int sin_size = sizeof(struct sockaddr_in); char buf[MAX]; int yes = 1; if ((listener_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } if (setsockopt(listener_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } my_addr.sin_family = AF_INET; my_addr.sin_port = htons(MYPORT); my_addr.sin_addr.s_addr = INADDR_ANY; memset(&(my_addr.sin_zero), '\0', 8); bind(listener_fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)); listen(listener_fd, BACKLOG); new_fd = accept(listener_fd, (struct sockaddr *)&their_addr, &sin_size); recv(new_fd, buf, MAX, 0); printf("Received from : %s\n%s\n",inet_ntoa(their_addr.sin_addr) ,buf); close(listener_fd); }
and now the client code :
Code:
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/time.h> #include <sys/types.h> #include <string.h> #include <unistd.h> #define PORT 3490 #define MAX 1000 /* mess max char */ #define MAXLINE 100 void getmess(char *mess); /* function that gets the user message */ main() { struct sockaddr_in server_addr; int sock_fd; int sin_size = sizeof(struct sockaddr_in); char mess[1000]; if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); memset(&(server_addr.sin_zero), '\0', 8); if (connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) { perror("connect"); exit(1); } i=getmess(mess); /* wait for full message, ending with "." */ if (send(sock_fd, mess, strlen(mess), 0) == -1) { /* send the message to the server */ perror("send"); exit(1); } close(sock_fd); } void getmess(char *mess) { char *last_line; int i=0; int comp; while( (last_line = fgets(mess+i,MAXLINE ,stdin)) != NULL && (comp = strcmp(last_line, ".\n")) != 0) i = (strrchr(mess, '\n') - mess) + 1; if (comp == 0) *(mess+i)='\0'; /* erase the "." from the message to send */ }
Now the problem is that, when the server receives a multiline message and prints it, a lot of garbage characters are also printed at the end.
For example if I send the message :
Code:
hello my name's axel .
the server will print :
Code:
hello my name's axel ÿö?p ?Ì¿ÿö
However, the server receives one-line messages (the second line being "." ) perfectly.

Any idea as to what's going wrong ?

Thx in advance for your help
     
Fresh-Faced Recruit
Join Date: Aug 2002
Status: Offline
Reply With Quote
Aug 5, 2002, 03:12 PM
 
Hi Axel,

What you're seeing is the "junk" characters of an uninitialized string buffer. When you allocate the "buf" string/array, the memory allocated to the buf variable contains 1000 (MAX) bytes of old junk - this memory area is not cleared for you. When you later make the call to recv, recv fills the first, say 100 bytes of this array with the actual characters, and the remaining 900 bytes contain the same old crud as before.

When you print buf, it prints all of the characters in it, both the data from recv, and all data beyond that up until it finds an "end of line" character. Since you haven't set an end of line character in buf (recv doesn't do that for you), it will either print all 1000 bytes of buf or less if one of the 900 (in my example) uninitialized bytes happen to contain an end of line character.

What you need to do is to find out how many bytes you got from your recv call, and then set an end of line character manually, like so:

int n = recv(new_fd, buf, MAX, 0);
buf[n] = '\0';

recv() returns the number of bytes read, so you know that the last "legitimate" character in buf resides at buf[n-1]. Setting the next character to the null character tells all of the string functions in C where the end of line is.

So, a long winded response but hopefully a clear one :-)

Cheers,
-Fredrik
     
Axel  (op)
Mac Enthusiast
Join Date: Sep 2000
Location: France
Status: Offline
Reply With Quote
Aug 5, 2002, 03:33 PM
 
Originally posted by karamellkungen:
Hi Axel,

What you're seeing is the "junk" characters of an uninitialized string buffer. When you allocate the "buf" string/array, the memory allocated to the buf variable contains 1000 (MAX) bytes of old junk - this memory area is not cleared for you. When you later make the call to recv, recv fills the first, say 100 bytes of this array with the actual characters, and the remaining 900 bytes contain the same old crud as before.

When you print buf, it prints all of the characters in it, both the data from recv, and all data beyond that up until it finds an "end of line" character. Since you haven't set an end of line character in buf (recv doesn't do that for you), it will either print all 1000 bytes of buf or less if one of the 900 (in my example) uninitialized bytes happen to contain an end of line character.

What you need to do is to find out how many bytes you got from your recv call, and then set an end of line character manually, like so:

int n = recv(new_fd, buf, MAX, 0);
buf[n] = '\0';

recv() returns the number of bytes read, so you know that the last "legitimate" character in buf resides at buf[n-1]. Setting the next character to the null character tells all of the string functions in C where the end of line is.

So, a long winded response but hopefully a clear one :-)

Cheers,
-Fredrik
Very clear indeed
Thx a lot for your help !
     
   
Thread Tools
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Top
Privacy Policy
All times are GMT -5. The time now is 06:08 PM.
All contents of these forums © 1995-2011 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.7 © 2000-2011, Jelsoft Enterprises Ltd., Content Relevant URLs by vBSEO 3.3.2