Simple network-programming program - not working
I just began learning network programming. My first program is very simple: once connected, the server program displays what the client program sends (characters). Everything works fine until they get connected. At first, I did the sending loop using putc:
while((c = getc(stdin)) != '\n')
putc(c, (FILE *) connection);
and the receiving one with getc:
while((c = getc((FILE *) connection)) != '\n')
putc(c, stdout);
Once connected, I get a segmentation fault. Then I tried using send:
while(1) {
memset(str, null, strlen(memset));
while(((c = getc(stdin)) != '\n') && sizeof(str) <= 100) {
strcat(str, (char *) c); // cast to char * is to make gcc happy
}
send(connection, (void *) str, sizeof(str), (int) NULL);
}
and recv:
while((stat = recv(connection,str,100,0)) != 0) {
printf("\nReceived %d bytes of data from %s: %s", stat, client, str);
}
Now recv() keeps returning -1 and errno is set to 107. What does this mean? Where am I doing wrong? By the way I'm using Linux with gcc.
Thanks a lot for your help! :)
EDIT: Even if I used getc() and putc(), I get connection with socket(), then I connect() (client). The server, after obtaining connection (with socket()) bind()s, then listen()s and accept()s. Sorry if I ometted.
Here's the server code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>
void main(int argc, char *argv[])
{
struct addrinfo hint;
struct addrinfo *servinfo, *count;
struct sockaddr_storage conn_addr;
struct sockaddr host;
int connessione;
int stat;
int conn_sock;
int conn_size;
int success;
int c;
char t[INET_ADDRSTRLEN];
char str[100];
char *client;
if(argc != 1 && strcmp(argv[1], "aiuto") == 0) {
printf("%s(porta)\n",argv[0]);
printf("porta: specifica su quale porta installarsi\n");
exit(-1);
}
memset(&hint,0,sizeof hint);
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
hint.ai_flags = AI_PASSIVE;
if((stat = getaddrinfo(NULL, argv[1], &hint, &servinfo)) != 0) {
printf("\n[FATAL]: getaddrinfo: %s",gai_strerror(stat开发者_C百科));
exit(-1);
}
success = 0;
for(count = servinfo; count != NULL; count = count->ai_next) {
if((connessione = socket(count->ai_family, count->ai_socktype, count->ai_protocol)) <= 0)
continue;
if((stat = bind(connessione, count->ai_addr, count->ai_addrlen)) == 0) {
success = 1;
break;
}
else {
continue;
}
}
if(success == 0) {
printf("\n[FATAL]: Unable to bind()!\n");
exit(-1);
}
else {
printf("\n[DEBUG]: %s: listening...", argv[0]);
}
servinfo = count;
freeaddrinfo(count);
if(listen(connessione, 20) == -1) {
printf("\n[FATAL]: listen: %s (%d)\n", gai_strerror(errno), errno);
close(connessione);
exit(-1);
}
conn_size = sizeof(conn_addr);
if(accept(connessione, (struct sockaddr *) &conn_addr, &conn_size) == -1) {
printf("\n[FATAL]: accept: %s", gai_strerror(errno));
close(connessione);
exit(-1);
}
client = (char *) malloc(INET_ADDRSTRLEN * sizeof(char));
client = inet_ntop(servinfo->ai_family, &conn_addr, t, INET_ADDRSTRLEN);
printf("\n[DEBUG]: %s: connection accepted: %s", argv[0], client);
while((stat = recv(connessione,str,100,0)) != 0) {
printf("\nReceived %d bytes of data from %s: %s", stat,client, str);
}
printf("\n[DEBUG]: connection closed by %s\n",client);
}
And the client's code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>
void main(int argc, char *argv[])
{
struct addrinfo hint;
struct addrinfo *servinfo, *count;
struct sockaddr_storage conn_addr;
struct sockaddr host;
int connessione;
int stat;
int conn_sock;
int conn_size;
int success;
int c;
char t[INET_ADDRSTRLEN];
char *indirizzo;
char str[100];
memset(&hint,0,sizeof hint);
host.sa_family = AF_INET;
if(inet_pton(host.sa_family, argv[1], (void *) host.sa_data) == -1) {
printf("\n[FATAL]: pton: %s (%d)\n", gai_strerror(errno), errno);
exit(-1);
}
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
hint.ai_flags = AI_PASSIVE;
hint.ai_addr = &host;
if((stat = getaddrinfo(argv[1], argv[2], &hint, &servinfo)) != 0) {
printf("[FATAL]: getaddrinfo: %s\n",gai_strerror(stat));
exit(-1);
}
success = 0;
for(count = servinfo; count != NULL; count = count->ai_next) {
if((connessione = socket(count->ai_family, count->ai_socktype, count->ai_protocol)) == -1)
continue;
if(connect(connessione, count->ai_addr, count->ai_addrlen) != -1) {
success = 1;
break;
}
}
if(success == 0) {
printf("\n[FATAL]: impossibile trovare l'host specificato\n");
exit(-1);
}
servinfo = count;
freeaddrinfo(count);
indirizzo = (char *) malloc(INET_ADDRSTRLEN * sizeof(char));
indirizzo = inet_ntop(servinfo->ai_family, &conn_addr, t, INET_ADDRSTRLEN);
printf("\n[DEBUG]: %s: connesso a: %s\n",argv[0], indirizzo);
while(1) {
strcpy(str,"buffer for data to send");
while(((c = getc(stdin)) != '\n') && sizeof(str) <= 100) {
strcat(str, (char *) c);
}
send(connessione, (void *) str, sizeof(str), (int) NULL);
}
}
At the end...
It works perfectly! Thanks everyone. :)
Normally you don't use a FILE *
handle to do network programming. Rather, you need a socket descriptor returned by the socket(2)
system call. Once you have it, you can either connect(2)
it (the client) or bind(2)
it (the server). The ongoing communication can be performed using recv(2)
and send(2)
.
If you really want to use a FILE *
handle to do network programming, take a look at the fdopen(3)
library function. It takes a descriptor that could be returned by socket(2)
and returns a FILE *
handle that is compatible with fread
/ fwrite
/ fprintf
.
After posting your full code, the most significant error that I could see was:
if (accept(connessione, (struct sockaddr *) &conn_addr, &conn_size))
accept(2)
returns a socket which you have to use with recv(2)
/ send(2)
, and you discard it, using the server socket instead.
I suggest You reading http://beej.us/guide/
This is a very nice guide to socket programming
When you use a cast (like (FILE *) connection
) you're telling the compiler: "trust me, this is the truth". When you lie to the compiler it believes you.
You have lied to the compiler. connection
is not a pointer to a FILE structure. A segmentation fault is the nicest result you can get, because it tells you something is badly wrong.
You make some programming errors:
1) memset(str, null, strlen(memset));
should be : memset( str ,0 ,sizeof(str) ); // if str is declared as char str[100];
2) while(((c = getc(stdin)) != '\n') && sizeof(str) <= 100)
shhould be : while(((c = getc(stdin)) != '\n') && (strlen(str) <= 100))
3) send(connection, (void *) str, sizeof(str), (int) NULL);
should be : send(connection, (void *) str, strlen(str), (int) NULL);
精彩评论