Hi I'm writing 2 Programs (Server, Client) which should communicate with each other over sockets. The Client is able to send its first message to the server with no problem, but when the server tries to answer, the client receives just an empty msg: recv(...) is 0.
The server suddenly stops after the send(...) function is called.
Here is my Code:
Server:
/* Create a new TCP/IP socket `sockfd`, and set the SO_REUSEADDR
option for this socket. Then bind the socket to localhost:portno,
listen, and wait for new connections, which should be assigned to
`connfd`. Terminate the program in case of an error.
*/
struct sockaddr_in sin,
peer_addr;
//-----gen socket-----//
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
bail_out(EXIT_PARITY_ERROR, "could not create Socket");
//-----bind-----//
memset(&sin, 0, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(options.portno);
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0)
bail_out(EXIT_PARITY_ERROR, "Failed to bind to Port");
//-----listen-----//
if (listen(sockfd, 5) < 0)
bail_out(EXIT_PARITY_ERROR, "Server can't accepted connection");
//-----accept-----//
int sock_len = sizeof peer_addr;
if ((connfd = accept(sockfd, (struct sockaddr*)&peer_addr, (socklen_t *)&sock_len)) < 0) //fragen
bail_out(EXIT_PARITY_ERROR, "Can't accept connection to Client");
/* accepted the connection */
//Some other Code which has nothing to do with my Error!
/* read from client (WORKS FINE!!)*/
if (read_from_client(connfd, &buffer[0], READ_BYTES) == NULL) {
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "read_from_client");
}
request = (buffer[1] << 8) | buffer[0];
DEBUG("Round %d: Received 0x%x\n", round, request);
/* compute answer */
correct_guesses = compute_answer(request, buffer, options.secret);
if (round == MAX_TRIES && correct_guesses != SLOTS) {
buffer[0] |= 1 << GAME_LOST_ERR_BIT;
}
DEBUG("Sending byte 0x%x\n", buffer[0]);
/* send message to client */
if (send_to_client(sockfd, &buffer[0], WRITE_BYTES) == NULL) { //Error in this Method!
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "can't send message!");
}
Methods:
static uint8_t *send_to_client(int fd, uint8_t *buffer, size_t n)
{
/* loop, as packet can arrive in several partial reads */
size_t bytes_send = 0;
do {
ssize_t r = send(fd, buffer + bytes_send, n - bytes_send, 0); //Program stops HERE!
printf("%d\n", (int)r); //This and the following lines will not be executed!
if (r <= 0) {
return NULL;
}
bytes_send += r;
} while (bytes_send < n);
if (bytes_send < n) {
return NULL;
}
return buffer;
}
Client: (Might be usefull)
sockfd = cnt_to_server(argv[1], argv[2]);
uint8_t buffer;
uint16_t msg_buffer;
do
{
msg_buffer = generate_msg(&msg);
printf("Sending byte 0x%x\n", msg_buffer);
if (send_to_server(sockfd, &msg_buffer, WRITE_BYTES) == NULL) //works
error_exit(EXIT_FAILURE, "can't send message!");
if (read_from_server(sockfd, &buffer, READ_BYTES) == NULL) //NULL
error_exit(EXIT_FAILURE, "can't read message!");
printf("received byte 0x%x\n", buffer);
} while (game_continue(buffer, &msg));
(void)close(sockfd);
Methods:
uint8_t* read_from_server(int fd, uint8_t *buffer, int n)
{
/* loop, as packet can arrive in several partial reads */
size_t bytes_recv = 0;
do {
ssize_t r;
r = recv(fd, buffer + bytes_recv, n - bytes_recv, 0); //0
printf("%d\n", (int)r);
if (r <= 0) {
return NULL;
}
bytes_recv += r;
} while (bytes_recv < n);
if (bytes_recv < n) {
return NULL;
}
return buffer;
}
int cnt_to_server(const char *par_server, const char *par_port)
{
struct sockaddr_in server;
struct hostent *hp;
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error_exit(EXIT_FAILURE, "could not create Socket");
server.sin_family = AF_INET;
if ((hp = gethostbyname(par_server)) == 0)
error_exit(EXIT_FAILURE, "host error!");
memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
server.sin_port = htons(parse_port(par_port));
if (connect(sockfd, (struct sockaddr*) &server, sizeof server) < 0)
error_exit(EXIT_FAILURE, "could not connect!");
return sockfd;
}
Thx for helping me out with this!
Change
if (send_to_client(sockfd, &buffer[0], WRITE_BYTES) == NULL)
to
if (send_to_client(connfd, &buffer[0], WRITE_BYTES) == NULL)
The solution is to use connfd (File descriptor for connection socket) instead of sockfd:
/* read from client */
if (read_from_client(connfd, &buffer[0], READ_BYTES) == NULL) {
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "read_from_client");
}
Related
I'm new to network programming and recently finished reading through Beej's guide. I have a client/server program that I'm trying to get to continuously have the server return the contents of a file when the client requests it.
It works by the client sending the server a file path and the server reading it (if it exists) into a buffer then sending the buffer to the client which just prints the buffer.
It works, but it will only return one file then ignores any following requests. I have to shut down the client and reconnect again for it to work again. I can't figure out why. I've tried implementing select() and used aio_read() over the standard read() and I also forking a process for the send() function. Each of those those experiments had it working exactly the same pretty much.
Anyone have any tips? I'm at a loss where the problem could be.
Client
#define MAXDATASIZE 100 // max number of bytes at once
#define MAXMSG 25
#define MAXDATA 4096
#define SA struct sockaddr
// clean_str: make sure the string doesn't have junk spaces around it
void clean_str(char *s)
{
size_t len = strlen(s);
char tmp[MAXMSG] = {0};
strncpy(tmp, s, len-1);
memset(s, 0, len);
strncpy(s, tmp, len-1);
}
int main(int argc, char **argv)
{
int sockfd, numbytes;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
char file_request[MAXMSG] = {0};
char file_buf[MAXDATA];
if (argc != 3) {
fprintf(stderr, "usage: client <hostname> <port>\n");
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// load the struct
if ((rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(EXIT_FAILURE);
}
// loop trhough all results and connect to the first one we can
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) < 0) {
close(sockfd);
perror("client: connect");
continue;
}
// if we make it here, we've got a connection
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
exit(EXIT_FAILURE);
}
inet_ntop(p->ai_family, (SA*)&p->ai_addr, s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo);
// stay connect until client exits
int n;
while (1) {
// make sure everything is cleared to minimize issues
memset(file_buf, 0, MAXDATA);
memset(file_request, 0, sizeof MAXMSG);
numbytes = 0;
// get client request from stdin
int b = read(STDIN_FILENO, file_request, MAXMSG);
if (b < 0) {
perror("client: read");
}
clean_str(file_request);
// send the request to the server
if ((numbytes = send(sockfd, file_request, strlen(file_request), 0)) < 0) {
perror("send");
exit(EXIT_FAILURE);
}
// now we wait for a response
while ((n = read(sockfd, file_buf, MAXDATA-1)) > 0)
printf("%s\n", file_buf);
if (n < 0) {
perror("read");
}
}
return 0;
}
Server
#define PORT 3490
#define MAXDATA 4096
#define FILENAME 256
#define SA struct sockaddr // for less messy casting
// get_file: open file, read contents info a buffer, return buffer
char *get_file(const char *path) {
int n, bytes;
static char buf[MAXDATA];
// try to open file
n = open(path, O_RDONLY);
if (n < 0) {
strcpy(buf, "problem opening file");
printf("%s\n", buf);
return buf;
}
// if exists, read it into buffer on
bytes = read(n, buf, sizeof buf-1);
if (bytes < 0) {
strcpy(buf, "problem reading file");
printf("%s\n", buf);
return buf;
}
close(n);
return buf;
}
int main()
{
int sockfd, filefd;
struct sockaddr_in servaddr;
struct sockaddr_storage client_addr;
socklen_t len;
int nbytes;
char file_request[FILENAME]; // buf to hold client's request string
// clear servaddr struct
memset(&servaddr, 0, sizeof servaddr);
servaddr.sin_family = AF_INET; // IPv4 for simplicity
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // use my IP
servaddr.sin_port = htons(PORT); // short, network by order
// create socket file descriptor
// #param3 is the protocol. 0 means TCP
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// bind the socket to the PORT
if (bind(sockfd, (SA*)&servaddr, sizeof servaddr) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
// this prevents the 'bind: address already in use' issue
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
perror("setsocket");
exit(EXIT_FAILURE);
}
if (listen(sockfd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("server running and waiting for connection...\n");
int open = 1; // keep track if there's an accepted() fd
char *open_file;
while (1) {
// clear the file_request buffer
memset(file_request, 0, FILENAME);
memset(&open_file, 0, sizeof open_file);
nbytes = 0;
if (open) {
// we're only going to connect to one client for now
len = sizeof client_addr;
filefd = accept(sockfd, (SA*)&client_addr, &len);
if (filefd < 0) {
perror("accept");
continue;
} else {
printf("connected to a client\n");
open = 0; // keep track that there's an open fd
}
}
// recieve data from a client
if ((nbytes = recv(filefd, file_request, sizeof file_request, 0)) <= 0) {
// got error or connection was closed by client
if (nbytes == 0) {
printf("file-server: client hung up\n");
close(filefd);
open = 1;
continue;
} else {
perror("recv");
close(filefd);
open = 1;
continue;
}
close(filefd);
} else {
// we got some data
// manage it and get file contents
open_file = get_file(file_request);
if (strcmp(open_file, "0") == 0) {
continue;
}
if (send(filefd, open_file, strlen(open_file), 0) < 0) {
perror("send");
continue;
}
}
}
close(sockfd);
return 0;
}
I have read some example and manual about select and accept but I still can't figure out where I did wrong.
I tried to let server communicate with multiple clients. But when I execute server first, then execute client, server will immediately cause segmentation fault( when i == sockfd in server.c). And I tried to print some strings to check which statement cause wrong, it even no print anything after if (i == sockfd). So I really have no idea how to move on, are there any suggestion?
Server.c
char inputBuffer[140] = {};
char message[] = {"Hi,this is server.\n"};
int sockfd = 0,forClientSockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("Fail to create a socket.");
}
//socket creation
struct sockaddr_in serverInfo,clientInfo;
socklen_t addrlen = sizeof(clientInfo);
serverInfo.sin_family = PF_INET;
serverInfo.sin_addr.s_addr = INADDR_ANY;
serverInfo.sin_port = htons(PORT);
bind(sockfd,(struct sockaddr *)&serverInfo,sizeof(serverInfo));
listen(sockfd,5);
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in clientname;
size_t size;
/* Initialize the set of active sockets. */
FD_ZERO (&active_fd_set);
FD_SET (sockfd, &active_fd_set);
int fd_max = sockfd;
while (1)
{
/* Block until input arrives on one or more active sockets. */
//FD_ZERO (&active_fd_set);
//FD_SET (sockfd, &active_fd_set);
read_fd_set = active_fd_set;
if (select (fd_max+1, &read_fd_set, NULL, NULL, NULL) < 0)
{
printf("select fail\n");
}
/* Service all the sockets with input pending. */
for (i = 0; i <= fd_max; ++i)
{
//printf("%d\n",i);
if (FD_ISSET (i, &read_fd_set))
{
//printf("inner :%d %d\n",i,sockfd);
if (i == sockfd)
{
/* Connection request on original socket. */
//printf("A");
int new;
size = sizeof (clientname);
new = accept (sockfd,(struct sockaddr *) &clientname,&size);
if (new < 0)
{
printf("accept fail\n");
}
else
{
printf (
"Server: connect from host %s, port %hd.\n",
inet_ntoa (clientname.sin_addr),
ntohs (clientname.sin_port));
FD_SET (new, &active_fd_set);
if(new > fd_max)
{
fd_max = new;
}
}
}
else
{
/* Data arriving on an already-connected socket. */
if (read_from_client (i) < 0)
{
close (i);
FD_CLR (i, &active_fd_set);
}
}
}
}
}
return 0;
}
int read_from_client (int filedes)
{
char buffer[140];
int nbytes;
nbytes = recv (filedes, buffer, sizeof(buffer),0);
if (nbytes < 0)
{
/* Read error. */
perror ("read");
exit (EXIT_FAILURE);
}
else if (nbytes == 0)
/* End-of-file. */
return -1;
else
{
/* Data read. */
printf ("Server: got message: `%s'\n", buffer);
return 0;
}
}
client.c
int sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("Fail to create a socket.");
}
//socket connnection
struct sockaddr_in info;
bzero(&info,sizeof(info));
info.sin_family = PF_INET;
//localhost test
info.sin_addr.s_addr = inet_addr(LOCALHOST);
info.sin_port = htons(PORT);
int err;
char *p;
//Send a message to server
err = connect(sockfd,(struct sockaddr *)&info,sizeof(info));
if(err==-1)
printf("Connection error");
while(1)
{
char message[140];
char receiveMessage[140] = {};
fgets(message,140,stdin);
//scanf("%*[^\n]",message);
//printf("%s",message);
/*if(p=strchr(message,'\n')){
*p = 0;
}else{
scanf("%*[^\n]");
scanf("%c");
}
fgets(message,140,stdin);*/
//scanf("%s",message);
send(sockfd,message,sizeof(message),0);
//printf("RCV");
//recv(sockfd,receiveMessage,sizeof(receiveMessage),0);
//printf("%s\n",receiveMessage);
}
thanks !!
I am new to both C and socket programming, so please bear with me. The following code is mostly from Beej networking guide, with some changes. I have the receiver code attached (which is TCP server in this case), that listens to multiple TCP connections. I have a transmitter (client) who is constantly sending fixed chunks of data to this receiver. This code (which I cleaned and removed some function definitions unrelated to my issue) works if instead of calling recv_all function, I only call recv(). But the problem with that I need to do processing on each chunk of received data, so I need the whole chunk. So I thought I should use the recv_all().
Now the problem is it gets stuck in an infinite loop in the while in recv_all(), because n is always 0. I truly appreciate your help.
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 20 // how many pending connections queue will hold
#define MAXDATASIZE 801 // max number of bytes we can get at once
int recv_all(int socket, char *buffer, int *length)
{
int total = 0; // how many bytes we've sent
int bytesleft = *length; // how many we have left to send
int n;
while(total < *length) {
n = recv(socket, buffer+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*length = total; // return number actually received here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
double buf[MAXDATASIZE];
int lenRecv;
struct sockaddr_in local_addr; // For the new addition to bind it to an interface
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
for (int i=0; i<1000000; i++) {
int rowInfoSize;
//if ((numbytes = recv(sockfd, buf, sizeof (buf), 0)) == -1) {
//if ((numbytes = recv(new_fd, buf, sizeof (buf), MSG_WAITALL)) == -1) { // I THINK THE BETTER WAY IS to CHECK THE OUTPUT AND LOOP UNTIL COMPLETE.
lenRecv = sizeof (buf);
//if (recv_all(new_fd, (char *)buf, &lenRecv) == -1) {
if (recv_all(new_fd, buf, &lenRecv) == -1) {
perror("sendall");
printf("We only sent %d bytes because of the error!\n", lenRecv);
}
}
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
You are ignoring end of stream. If n == 0 the peer has disconnected. Your code will loop forever.
Throw it all away and use recv() with the MSG_WAITALL option.
give recv_all a timeout value
int recv_all(int socket, char *buffer, int *length, int timeout)
and use select before recv()
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
looks like this
int recv_all(int socket, char *buffer, int *length)
{
int total = 0; // how many bytes we've sent
int bytesleft = *length; // how many we have left to send
int n = -1;
struct timeval timeout;
fd_set rset;
int rc;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
while(total < *length) {
FD_ZERO(&rset);
FD_SET(socket, &rset);
rc = select(socket + 1, &rset, NULL, NULL, &timeout);
if(rc < 0)
{
// errno
n = -1;
break;
}
if(0 == rc)
{
// timeout
n = -1;
break;
}
if(FD_ISSET(socket, &rset))
{
n = recv(socket, buffer+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
}
}
*length = total; // return number actually received here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
Two clients are able to connect to the server but it is only accepting and displaying input stream messages for the first client and not for the second, though the other client is also connected.
Following is the code where i am accepting the stream, i have tried closing the socket each tie but it is not working out.
int main(int argc,char *argv[])
{
fd_set ready;
struct sockaddr_in msgfrom;
int msgsize;
union {
uint32_t addr;
char bytes[4];
} fromaddr;
if ((progname = rindex(argv[0], '/')) == NULL)
progname = argv[0];
else
progname++;
while ((ch = getopt(argc, argv, "adsp:h:")) != -1)
switch(ch) {
case 'a':
aflg++; /* print address in output */
break;
case 'd':
soctype = SOCK_DGRAM;
break;
case 's':
server = 1;
break;
case 'p':
port = optarg;
break;
case 'h':
host = optarg;
break;
case '?':
default:
usage();
}
argc -= optind;
if (argc != 0)
usage();
if (!server && (host == NULL || port == NULL))
usage();
if (server && host != NULL)
usage();
/*
* Create socket on local host.
*/
if ((s = socket(AF_INET, soctype, 0)) < 0) {
perror("socket");
exit(1);
}
sock = setup_server();
while (!done) {
FD_ZERO(&ready);
FD_SET(sock, &ready);
FD_SET(fileno(stdin), &ready);
if (select((sock + 1), &ready, 0, 0, 0) < 0) {
perror("select");
exit(1);
}
if (FD_ISSET(fileno(stdin), &ready)) {
if ((bytes = read(fileno(stdin), buf, BUF_LEN)) <= 0)
done++;
send(sock, buf, bytes, 0);
}
msgsize = sizeof(msgfrom);
if (FD_ISSET(sock, &ready)) {
if ((bytes = recvfrom(sock, buf, BUF_LEN, 0, (struct sockaddr *)&msgfrom, &msgsize)) <= 0) {
done++;
} else if (aflg) {
fromaddr.addr = ntohl(msgfrom.sin_addr.s_addr);
fprintf(stderr, "%d.%d.%d.%d: ", 0xff & (unsigned int)fromaddr.bytes[0],
0xff & (unsigned int)fromaddr.bytes[1],
0xff & (unsigned int)fromaddr.bytes[2],
0xff & (unsigned int)fromaddr.bytes[3]);
}
write(fileno(stdout), buf, bytes);
}
}
Here is the code where i am setting up my server, for reference:
int setup_server() {
struct sockaddr_in serv, remote;
struct servent *se;
int newsock, len;
len = sizeof(remote);
memset((void *)&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
if (port == NULL)
serv.sin_port = htons(9990);
else if (isdigit(*port))
serv.sin_port = htons(atoi(port));
if (bind(s, (struct sockaddr *)&serv, sizeof(serv)) < 0) {
perror("bind");
exit(1);
}
if (getsockname(s, (struct sockaddr *) &remote, &len) < 0) {
perror("getsockname");
exit(1);
}
fprintf(stderr, "Port number is %d\n", ntohs(remote.sin_port));
listen(s, 1);
newsock = s;
if (soctype == SOCK_STREAM) {
fprintf(stderr, "Entering accept() waiting for connection.\n");
newsock = accept(s, (struct sockaddr *) &remote, &len);
}
return(newsock);
}
Client code:
sock = setup_client();
/*
* Set up select(2) on both socket and terminal, anything that comes
* in on socket goes to terminal, anything that gets typed on terminal
* goes out socket...
*/
while (!done) {
FD_ZERO(&ready);
FD_SET(sock, &ready);
FD_SET(fileno(stdin), &ready);
if (select((sock + 1), &ready, 0, 0, 0) < 0) {
perror("select");
exit(1);
}
if (FD_ISSET(fileno(stdin), &ready)) {
if ((bytes = read(fileno(stdin), buf, BUF_LEN)) <= 0)
done++;
send(sock, buf, bytes, 0);
}
msgsize = sizeof(msgfrom);
if (FD_ISSET(sock, &ready)) {
if ((bytes = recvfrom(sock, buf, BUF_LEN, 0, (struct sockaddr *)&msgfrom, &msgsize)) <= 0) {
done++;
} else if (aflg) {
fromaddr.addr = ntohl(msgfrom.sin_addr.s_addr);
fprintf(stderr, "%d.%d.%d.%d: ", 0xff & (unsigned int)fromaddr.bytes[0], 0xff & (unsigned int)fromaddr.bytes[1],
0xff & (unsigned int)fromaddr.bytes[2],
0xff & (unsigned int)fromaddr.bytes[3]);
}
write(fileno(stdout), buf, bytes);
}
//close(sock);
}
return(0);
}
/*
* setup_client() - set up socket for the mode of soc running as a
* client connecting to a port on a remote machine.
*/
int setup_client() {
struct hostent *hp, *gethostbyname();
struct sockaddr_in serv;
struct servent *se;
/*
* Look up name of remote machine, getting its address.
*/
if ((hp = gethostbyname(host)) == NULL) {
fprintf(stderr, "%s: %s unknown host\n", progname, host);
exit(1);
}
/*
* Set up the information needed for the socket to be bound to a socket on
* a remote host. Needs address family to use, the address of the remote
* host (obtained above), and the port on the remote host to connect to.
*/
serv.sin_family = AF_INET;
memcpy(&serv.sin_addr, hp->h_addr, hp->h_length);
if (isdigit(*port))
serv.sin_port = htons(atoi(port));
else {
if ((se = getservbyname(port, (char *)NULL)) < (struct servent *) 0) {
perror(port);
exit(1);
}
serv.sin_port = se->s_port;
}
/*
* Try to connect the sockets...
*/
if (connect(s, (struct sockaddr *) &serv, sizeof(serv)) < 0) {
perror("connect");
exit(1);
} else
fprintf(stderr, "Connected...\n");
return(s);
}
UDP is ok, you can just recvfrom() like you're doing already.
TCP is different, but you're almost there: you need a call to accept() for every connection you wish to handle, ie you shold select() the server socket in the loop, call accept() on it as necessary to get a new socket, deal with it and close() it at the end.
On the client's side it looks like you connected because you're in the server's queue of pending connections -- see the listen(2) manpage.
I'm trying to make a server that can be connected to by multiple clients. Here's my code so far:
Client:
int main(int argc, char **argv) {
struct sockaddr_in servaddr;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) perror("Socket");
bzero((void *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6782);
servaddr.sin_addr.s_addr = inet_addr(<server_ip_address>);
if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)))
perror("Connect");
while(1) {
char message[6];
fgets(message, 6, stdin);
message[5] = '\0';
send(sock, message, 6, 0);
}
close(sock);
}
Server:
int main(int argc, char **argv) {
fd_set fds, readfds;
int i, clientaddrlen;
int clientsock[2], rc, numsocks = 0, maxsocks = 2;
int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serversock == -1) perror("Socket");
struct sockaddr_in serveraddr, clientaddr;
bzero(&serveraddr, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(6782);
if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,
sizeof(struct sockaddr_in)))
perror("Bind");
if (-1 == listen(serversock, SOMAXCONN))
perror("Listen");
FD_ZERO(&fds);
FD_SET(serversock, &fds);
while(1) {
readfds = fds;
rc = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
if (rc == -1) {
perror("Select");
break;
}
for (i = 0; i < FD_SETSIZE; i++) {
if (FD_ISSET(i, &readfds)) {
if (i == serversock) {
if (numsocks < maxsocks) {
clientsock[numsocks] = accept(serversock,
(struct sockaddr *) &clientaddr,
(socklen_t *)&clientaddrlen);
if (clientsock[numsocks] == -1) perror("Accept");
FD_SET(clientsock[numsocks], &fds);
numsocks++;
} else {
printf("Ran out of socket space.\n");
}
} else {
int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
while ((in = recv(clientsock[i], &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
}
}
}
}
close(serversock);
return 0;
}
As soon as a client connects and sends its first message, the server just runs in an infinite loop, and spits out garbage from the message array. recv doesn't seem to receive anything. Can anyone see where i go wrong?
Two issues in your code:
You should do recv(i, ...) instead of recv(clientsock[i], ...)
After that you do not check if recv() failed, and therefore printf() prints out the uninitialised buffer message, hence the garbage in the output
You need to check for limit <= 0 in your read loop, before you call read.
In the while loop for the server, change the code to do recv(i) instead of recv(clientsocks[i]). I have implemented this code and it works with this change.
I replaced the else with the below and it works
} else {
/* int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
memset ( &message[index] , 0, sizeof ( message [index] ) );
while ((in = recv(i, &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
*/
bzero(buf, sizeof(buf));
if ((rval = read(i, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
}
1) It is a good practice to use PF_INET(protocol family) rather than
AF_INET(address family) during the Socket creation .
2) within the while(1) loop
each time it is advisable to make your readfds empty by using FD_ZERO(&readfds).
in the recv() call you should use i rather than clientsocks[i]
you have to check return value of recv is negative(which indicating error in reading) if that is the case you do not have to print the message.
during printing the message make sure the stdout/server is ready for writing anything to it which you can do it by using writefds (3rd argument of select).