I have a program that is supposed to both read a serial port and from tcp/ip socket simultaneously.
However, I only can see the serial information when I receive a message via socket. I believe that it has something to do with blocking/nonblocking of the accept() method. However, I have been unsuccessful in figuring out how to add flags to it.
Anyone have any ideas?
Do I have to rewrite the whole thing or can I just add a flag?
int main(int argc, char *argv[]) {
int list_s; /* listening socket */
int conn_s; /* connection socket */
short int port; /* port number */
struct sockaddr_in servaddr; /* socket address structure */
char buffer[MAX_LINE]; /* character buffer */
char *endptr; /* for strtol() */
/* Get port number from the command line, and
* set to default port if no arguments were supplied */
if ( argc == 2 ) {
port = strtol(argv[1], &endptr, 0);
if ( *endptr ) {
fprintf(stderr, "ECHOSERV: Invalid port number.\n");
exit(EXIT_FAILURE);
}
}
else if ( argc < 2 ) {
port = ECHO_PORT;
}
else {
fprintf(stderr, "ECHOSERV: Invalid arguments.\n");
exit(EXIT_FAILURE);
}
/* Create the listening socket */
if ( (list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
/* Set all bytes in socket address structure to
* zero, and fill in the relevant data members */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
/* Bind our socket addresss to the
* listening socket, and call listen() */
if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling bind()\n");
exit(EXIT_FAILURE);
}
if ( listen(list_s, LISTENQ) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling listen()\n");
exit(EXIT_FAILURE);
}
/* Enter an infinite loop to respond
* to client requests and echo input */
int result = 0;
int portID = -1;
char *device = "/dev/ttyUSB1";
int rate = convertRate("115200");
char parity = convertParity("N");
int databits = convertDatabits("8");
int stopbits = convertStopbits("1");
portID = posixComOpen(device,rate,parity,databits,stopbits);
while ( 1 ) {
char input = 0;
while(posixComDataReady(portID) && posixComRead(portID, &input)) {
printf("%c", input);
} //while
/* Write character to Vex */
if(posixComWrite(portID, 'x') < 0)
printf("POSIX: Error Writing char %c",'x');
/* Wait for a connection, then accept() it */
if ( (conn_s = accept(list_s, NULL, NULL) ) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling accept()\n");
exit(EXIT_FAILURE);
}
/* Retrieve an input line from the connected socket
* then simply write it back to the same socket. */
Readline(conn_s, buffer, MAX_LINE-1);
printf("Netbook got a TCP/IP message: %s\n", buffer);
char* sendMessage = "Thanks for the message!";
Writeline(conn_s,sendMessage , strlen(sendMessage));
/* Close the connected socket */
if ( close(conn_s) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling close()\n");
exit(EXIT_FAILURE);
}
}//while
return 0;
}
You're right, the problem is that accept blocks until there is a new connection.
I don't know how serial connections work, but you might want to look at the select function, which allows you to wait on several different file descriptors, and respond to them when there is data on the other end.
Here's an example of how to use select for sockets: Server Example
Related
I am writing a TCP client and server protocol for a school project. The client sends a "GET \r\n" message and the server has to transfer "+OK\r\n", size of the file and the file, in case it exists in the server directory. I'm blocked in the file transfer
I tried to solve it at small steps at a time. I set up the connection, sent the request from the client and received the "OK" message from the server.
Now I opened the file in the server and tried to send it 128 bytes at a time to the client. The reading of the file works and apparently also the sending of the buffers but the client is not receiving anything...
Here's my server.c
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "../errlib.h"
#include "../sockwrap.h"
#define BUFLEN 128 /* Buffer length */
#define TIMEOUT 15 /* TIMEOUT */
/* FUNCTION PROTOTYPES */
void service(int s);
/* GLOBAL VARIABLES */
char *prog_name;
int main(int argc, char *argv[])
{
int conn_request_skt; /* passive socket */
uint16_t lport_n, lport_h; /* port used by server (net/host ord.) */
int bklog = 2; /* listen backlog */
int s; /* connected socket */
fd_set cset; // waiting for connection
struct timeval tval; // timeout
size_t n;
socklen_t addrlen;
struct sockaddr_in saddr, caddr; /* server and client addresses */
prog_name = argv[0];
if (argc != 2) {
printf("Usage: %s <port number>\n", prog_name);
exit(1);
}
/* get server port number */
if (sscanf(argv[1], "%" SCNu16, &lport_h)!=1)
err_sys("Invalid port number");
lport_n = htons(lport_h);
/* create the socket */
printf("creating socket...\n");
s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("done, socket number %u\n",s);
/* bind the socket to any local IP address */
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = lport_n;
saddr.sin_addr.s_addr = INADDR_ANY;
showAddr("Binding to address", &saddr);
Bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
printf("done.\n");
/* listen */
printf ("Listening at socket %d with backlog = %d \n",s,bklog);
Listen(s, bklog);
printf("done.\n");
conn_request_skt = s;
/* main server loop */
for ( ; ; )
{
printf("waiting for connection...\n");
/* accept next connection */
FD_ZERO(&cset);
FD_SET(conn_request_skt, &cset);
tval.tv_sec = TIMEOUT;
tval.tv_usec = 0;
n = Select(FD_SETSIZE, &cset, NULL, NULL, &tval);
if ( n > 0 ){
addrlen = sizeof(struct sockaddr_in);
s = Accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
showAddr("Accepted connection from", &caddr);
printf("new socket: %u\n",s);
/* serve the client on socket s */
service(s);
} else {
printf("No connection request after %d seconds\n",TIMEOUT);
}
}
}
void service(int s) {
char buf[BUFLEN]; /* reception buffer */
char filename[BUFLEN];
int n;
long filesize;
uint32_t fsize;
FILE *fp;
for ( ; ; )
{
n = recv(s, buf, BUFLEN, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("Received request from socket %03d :\n", s);
sscanf(buf, "GET %s\r\n", filename);
strcpy(buf, "+OK\r\n");
printf("%s",buf);
if(writen(s, buf, strlen(buf)) != strlen(buf))
printf("Write error while sending +OK\n");
// open file
fp = fopen(filename, "r");
if( fp == NULL){
//TODO close connection
}
// calculating dim of file
fseek(fp, 0L, SEEK_END);
filesize = ftell(fp);
rewind(fp); // go back at beginning of file
fsize = htonl(filesize); // size file in network byte order
// sending file size
if(writen(s, &fsize, 4) != 4)
printf("Write error while sending file size\n");
while(fread(buf, 1, BUFLEN - 1, fp) == BUFLEN - 1){
printf("%s", buf);
if(writen(s, buf, strlen(buf)) != strlen(buf))
printf("Write error while buf\n");
}
printf("%s", buf);
printf("I am here\n");
}
}
}
While here is my client.c
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "../errlib.h"
#include "../sockwrap.h"
#define BUFLEN 128 /* BUFFER LENGTH */
#define TIMEOUT 15 /* TIMEOUT*/
/* GLOBAL VARIABLES */
char *prog_name;
int main(int argc, char *argv[])
{
char request[BUFLEN]; /* request buffer */
char rbuf[BUFLEN]; /* reception buffer */
uint32_t taddr_n; /* server IP addr. (net/host ord) */
uint16_t tport_n, tport_h; /* server port number (net/host ord) */
int s, len;
int result;
struct sockaddr_in saddr; /* server address structure */
struct in_addr sIPaddr; /* server IP addr. structure */
fd_set cset; // variables for timeout
struct timeval tval;
size_t n;
prog_name = argv[0];
if(argc < 4)
err_sys("Wrong number of parameters!\n");
// read address from first argument
taddr_n = inet_addr(argv[1]);
if (taddr_n == INADDR_NONE)
err_sys("Invalid address");
// read port number from second argument
if (sscanf(argv[2], "%" SCNu16, &tport_h)!=1)
err_sys("Invalid port number");
tport_n = htons(tport_h);
/* create the socket */
printf("Creating socket\n");
s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("done. Socket fd number: %d\n",s);
/* prepare address structure */
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = tport_n;
saddr.sin_addr = sIPaddr;
printf("trying to connect to the server...\n");
/* connect */
showAddr("Connecting to target address", &saddr);
Connect(s, (struct sockaddr *) &saddr, sizeof(saddr));
printf("done.\n");
// loop to request files
for (int i = 3 ; i < argc ; i++ ){ // i = 4 because the first file is the fourth argument
// check if file name is too big
if(strlen(argv[i]) >= BUFLEN - 6)
err_sys("The file name is too big for the buffer request!\n");
// create the string of bytes for the request
strcpy(request, "GET ");
strcat(request, argv[i]);
strcat(request, "\r\n");
len = strlen(request);
if(writen(s, request, len) != len){
printf("Write error\n");
break;
}
printf("waiting for response...\n");
// receive file from server
n = recv(s, rbuf, BUFLEN, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("Received reply from server\n");
uint32_t fsize;
printf("%s",rbuf);
if(strcmp(rbuf, "+OK\r\n") == 0){
n = recv(s, &fsize, 4, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
// received file dimension
fsize = ntohl(fsize);
}
while(fsize > 0){
printf("I am here1n\n");
// receive file
n = recv(s, rbuf, BUFLEN-1, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("I am here");
fsize -= n;
}
}
}
}
}
printf("===========================================================\n");
close(s);
exit(0);
}
The recv in the client where I am supposed to receive the file just blocks without receiving anything. I don't understand what I am missing...
The issue here is a common one: You're not being careful with message boundaries.
In your client, you do a recv and check whether the number of bytes is greater than 0. But then you don't do more length checking. You next do a strcmp on a particular string you're expecting to receive (+OK\r\n). But you might have received 3 bytes (+OK) or you might have received 10: (+OK\r\nXXXXX) or more [aside: also, recv doesn't guarantee your byte string is null-terminated]. There is nothing stopping the kernel on the far side from batching the preamble plus subsequent bytes into a single TCP packet. Likewise, there is nothing preventing the local side from aggregating multiple TCP packets into a single buffer.
You must provide message boundaries. If you're expecting your next message to be 5 bytes, then you should receive exactly 5 bytes (and retry if you get fewer -- being careful to check for EOF too in case the other side aborted early). Or, alternatively stick a buffering layer in front of your receive logic so that it will receive up to some large amount, return to you the number of bytes you want, and then save whatever is in excess for a subsequent "receive" call.
To restate this in a different way: Your server sends +OK\r\n, then it sends a four-byte length, then it starts sending the file. But that means your first recv on the client side could be receiving the preamble, plus the length, plus the first N bytes of the file all in one system call.
TCP does not respect, provide or enforce message boundaries.
I coded a UDP socket client-server in C. The client sent a query to the server each second for a long time (e.g.: 1 week).
My code ran fine, but I can see in the timeline that the ram increased considerably, at around 14 hours the memory increased to 150M approximately.
The increment is in the client side, the server is working fine.
I need to detect what causes this problem because the program will be running for long time.
What's wrong in my code?
This is my code in the client side:
int consultar_servidor(char *t1_str_)
{
struct timeval t_ini, t_fin, tv;
double secs;
char cadena_enviada[67];
char cadena_recibida[67];
char tx_str[51]= "|0000000000000000|0000000000000000|0000000000000000";
int validacion, i;
long long int t4;
char t4_str[20];
char t2_str_rec[20];
char t2_pps_str_rec[20];
char t3_str_rec[20];
int nBytes, numfd;
if (t1_str_ != 0)
{
strcpy(cadena_enviada,t1_str_);
strcat(cadena_enviada,tx_str);
}
else
{
error("Error recepcion t1");
return 1;
}
if (cont_parametros == 0)
{
set_param();
}
if ( connect( clientSocket, ( struct sockaddr * ) &serverAddr, sizeof( serverAddr) ) < 0 )
error( "Error connecting socket" );
if ( sendto(clientSocket,cadena_enviada,sizeof(cadena_enviada),0,(struct sockaddr *)&serverAddr,addr_size) < 0)
{
close(clientSocket);
error( "Error sentto function");
cont_parametros = 0;
return 1;
}
/** Socket nonblock **/
int flags = fcntl(clientSocket, F_GETFL, 0);
fcntl(clientSocket, F_SETFL, flags | O_NONBLOCK);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(clientSocket, &readfds);
numfd = clientSocket + 1;
/** Set 700us to receive **/
tv.tv_sec=0;
tv.tv_usec=700000;
/** Server send me **/
int recibo = select(numfd, &readfds,NULL,NULL,&tv);
switch (recibo)
{
case -1:
/** Error reception **/
error("Error reception");
FD_CLR(clientSocket, &readfds);
close(clientSocket);
cont_parametros=0;
return 1;
case 0:
/** Timeout and close socket **/
error( "Error timeout" );
FD_CLR(clientSocket, &readfds);
close(clientSocket);
cont_parametros = 0;
return 1;
default:
/** If socket contain data **/
if (FD_ISSET(clientSocket, &readfds))
{
/** catch t4 **/
t4=ts();
sprintf(t4_str, "%lld", t4);
/** Receive server message**/
nBytes = recvfrom(clientSocket,cadena_recibida,sizeof(cadena_recibida),0,NULL, NULL);
/** If si a bad data **/
if (nBytes < 0)
{
error( "Error recept data" );
FD_CLR(clientSocket, &readfds);
close(clientSocket);
cont_parametros = 0;
return 1;
}
/** Clean set **/
FD_CLR(clientSocket, &readfds);
int i;
/** trim t2**/
for(i=17;i<33;i++) t2_str_rec[i-17]=cadena_recibida[i];
t2_str_rec[16]= '\0';
/** trim t3**/
for(i=34;i<51;i++) t3_str_rec[i-34]=cadena_recibida[i];
t3_str_rec[16]= '\0';
printf("%s|%s|%s|%s\n",t1_str_, t2_str_rec, t3_str_rec, t4_str);
return 0;
}
}
}
And the function to set the params socket:
void set_param()
{
/** Set client params **/
memset(&local_addr, 0, sizeof(struct sockaddr_in));
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(SRC_PORT);
local_addr.sin_addr.s_addr = inet_addr(SRC_IP);
/** Configure settings in address struct **/
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(DST_PORT);
serverAddr.sin_addr.s_addr = inet_addr(DST_IP);
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
addr_size = sizeof serverAddr;
clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if ( clientSocket < 0 )
{
error( "Error socket no create" );
exit(1);
}
if (bind(clientSocket, (struct sockaddr *)&local_addr, sizeof(local_addr))< 0)
{
close(clientSocket);
error( "Error bind in socket" );
exit(1);
}
/** Socket create OK**/
cont_parametros = 1;
}
The main part
int main( int argc, char* argv[] )
{
long long int t1;
char t1_str[20];
while(1)
{
t1=ts();
sprintf(t1_str, "%lld", t1);
consultar_servidor(t1_str);
sleep(1);
}
}
The main problem is that you call
close(clientSocket);
for all branches of the code except when you successfully read the data with recvfrom and return with code 0 from consultar_servidor(). As a result, the socket is never closed and there is a socket descriptor leak.
There may be other bugs in the code, make sure to test it under valgrind.
I suggest to restructure the code to avoid duplication and help to catch bugs such as these. For example, one option is to move the cleanup code to a separate function. Another option is to use the goto cleanup pattern, unless you're paranoid about not having goto in your code.
I don't see any actual memory allocations in the posted code, so if there is a direct memory leak, it must be caused by a problem somewhere else in the program.
As #kfx mentioned, another possibility is a socket leak; since each socket comes with buffers that use up a certain amount of RAM, that could show up as increased memory usage as well.
An easy way to test to see if your program is leaking sockets would be to add something like this to your program:
static int socketCount = 0;
int debug_socket(int domain, int type, int protocol)
{
int ret = socket(domain, type, protocol);
if (ret >= 0)
{
++socketCount;
printf("After socket() call succeeded, there are now %i sockets in use by this program\n", socketCount);
}
else perror("socket() failed!");
return ret;
}
int debug_close(int sock)
{
int ret = close(sock);
if (ret == 0)
{
--socketCount;
printf("After close() call succeeded, there now %i sockets in use by this program\n", socketCount);
}
else perror("close() failed!");
return ret;
}
... then temporarily replace all the calls to socket() in your program with debug_socket(), and all the calls to close() in your program with debug_close().
Then run your program, and watch its stdout output. If the numbers printed in the debug output are constantly increasing, your program is leaking sockets and you'll need to figure out why/how and fix it. If not, then you have some other problem elsewhere.
have a stand alone PC running VS6 on WinXP - yes ancient technology.
I am porting a C code app from Linux.
Stuck on multicast problem
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h> /* for printf(), fprintf() */
#include <conio.h>
#include <winsock.h> /* for socket(),... */
#include <stdlib.h> /* for exit() */
#define MAXRECVSTRING 255 /* Longest string to receive */
int main(int argc, char* argv[])
{
char msg[100];
char loopchar = 0;
int iOptVal = 0;
char iOptVal2 = 1;
int iLenOptVal = sizeof(int);
int result = -1;
int retval = -1;
int set_option_on = 1;
int sock; /* Socket */
struct sockaddr_in multicastAddr; /* Multicast Address */
char *multicastIP; /* IP Multicast Address */
unsigned short multicastPort; /* Port */
char recvString[MAXRECVSTRING+1]; /* Buffer for received string */
unsigned int recvStringLen; /* Length of received string */
struct ip_mreq multicastRequest; /* Multicast address join structure */
WSADATA wsaData; /* Structure for WinSock setup communication */
if (argc != 3) /* Test for correct number of arguments */
{
fprintf(stderr,"Usage: %s <Multicast IP> <Multicast Port>\n", argv[0]);
exit(1);
}
multicastIP = argv[1]; /* First arg: Multicast IP address (dotted quad) */
//WW Silversilsied //WW SilversilsiedmulticastIP = inet_addr("224.000.010.101"); /* First arg: Multicast IP address (dotted quad) */
//multicastIP = inet_addr("224.000.010.101"); /* First arg: Multicast IP address (dotted quad) */
multicastPort = atoi(argv[2]);/* Second arg: Multicast port */
//multicastPort = 6600);/* Second arg: Multicast port */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) /* Load Winsock 2.0 DLL */
{
fprintf(stderr, "WSAStartup() failed");
exit(1);
}
/* Create a best-effort datagram socket using UDP */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf("\nsocket() failed - error = %d\n", sock);
}
/* Construct bind structure */
memset(&multicastAddr, 0, sizeof(multicastAddr)); /* Zero out structure */
multicastAddr.sin_family = AF_INET; /* Internet address family */
multicastAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
multicastAddr.sin_port = htons(multicastPort); /* Multicast port */
/* Bind to the multicast port */
retval = bind(sock, (struct sockaddr *) &multicastAddr, sizeof(multicastAddr));
if (retval < 0)
{
printf("\nbind() failed - error = %d\n", retval);
}
#if 0
/* Specify the multicast group */
multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastIP);
/* Accept multicast from any interface */
multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
/* Join the multicast address */
//if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicastRequest, sizeof(multicastRequest)) < 0)
result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&set_option_on, sizeof(set_option_on));
if (result < 0)
{
printf("\n setsockopt() failed");
perror(" setsockopt ");
}
/* Receive a single datagram from the server */
while(1)
{
if ((recvStringLen = recvfrom(sock, recvString, MAXRECVSTRING, 0, NULL, 0)) < 0)
{
printf("\nrecvfrom() failed");
}
Sleep(1000);
}
#else
strcpy(msg,"default test message");
struct sockaddr_in address1;
int len;
int bytes_sent = -1;
memset(&address1, 0, sizeof(address1));
address1.sin_family = AF_INET;
address1.sin_port = multicastPort;
address1.sin_addr.s_addr = inet_addr(multicastIP);
//msg = "abcdefghijklmnopqrstuvwxyz";
//socklen_t len;
//size = strlen(msg);
if ((recvStringLen = recvfrom(sock, recvString, 1024, 0, (struct sockaddr*)&address1, &len)) < 0)
{
printf("\nrecvfrom() failed ");
perror(" recvfrom ");
}else{
recvString[recvStringLen] = '\0';
printf("Received: %d bytes %s\n", recvStringLen,recvString); /* Print the received string */
perror(" received from ");
}
bytes_sent = sendto(sock,
msg,
sizeof(msg),
0,
(struct sockaddr*)&address1,
sizeof(address1));
printf("bytes sent = %d \n", bytes_sent);
printf("size of msg = %d \n ", sizeof(msg));
perror( "sendto ");
#endif
getch();
closesocket(sock);
WSACleanup(); /* Cleanup Winsock */
exit(0);
return 0;
}
When I single step through, I get a successful socket creation and valid socket descriptor.
I get a successful bind, at which point the port shows up as udp when I do a cmd line netstat -p UDP -a
setsockopt also completes without error.
When I step through the recvfrom it receives 2^24 bytes all of which are the same -52
The machine is stand alone, not on a network.
recvString is 256 bytes long, but your recvFrom() is asking for up to 1024 bytes.
I've got an assignment to write a server program that accepts multiple clients. I'm writing in C language and trying to accomplish this using a select() statement. I am able to compile, but whenever I telnet in, I get a "Socket operation on non-socket error." I've tried researching the error, but can't find anything too helpful. Any assistance would be appreciated.
The output of my server is:
$ ./assign2 33333
Waiting for connection...
fd is 0
EchoServ recv error: Socket operation on non-socket
fd is 1
EchoServ recv error: Socket operation on non-socket
EchoServ recv error: Socket operation on non-socket
The output of telnet is:
$ telnet localhost 33333
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
Welcome to EchoServ chat.
My server code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define PORT 50000
main( int argc, char *argv[] )
{
char buf[ BUFSIZ ], /* buffer for incoming data */
*endptr, /* for strtol() */
*message = "Welcome to EchoServ chat. \r\n"; /* welcome message */
int masterSocket, /* main listening socket for server */
newSocket, /* new sockets for connecting clients */
opt = 1, /* for port reuse code */
nBytes, /* # of incoming bytes */
addrlen;
int i,j; /* temp vars */
short int port; /* port number */
fd_set master; /* master file descriptor list */
fd_set temp_fds; /* temp file descriptor list for select() */
int fdmax; /* maximum file descriptor number */
struct sockaddr_in sin;
/* Get port number from the command line, or
set to default port if no arguments were supplied */
if ( argc == 2 ) {
port = strtol(argv[1], &endptr, 0);
if ( *endptr ) {
fprintf(stderr, "EchoServ: Invalid port number.\n");
exit(EXIT_FAILURE);
}
}
else {
port = PORT;
}
FD_ZERO(&master); /* clear the master and temp sets */
FD_ZERO(&temp_fds);
/* Get an internet domain socket */
if ( ( masterSocket = socket( AF_INET, SOCK_STREAM, 0) ) == -1 ) {
perror( "EchoServ socket error" );
exit( 1 );
}
/* Complete the socket structure */
memset( &sin, 0, sizeof(sin) );
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
/* Bind the socket to the port number */
if ( bind( masterSocket, ( struct sockaddr *) &sin, sizeof( sin ) ) == -1) {
perror( "EchoServ bind failed" );
exit( 1 );
}
/* Allow port reuse */
if ( setsockopt( masterSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) ) == -1 ) {
perror( "EchoServ setsockopt error" );
exit(1);
}
/* Listen for clients that want to connect. */
if ( listen( masterSocket, 5 ) == -1 ) {
perror( "EchoServ listen error" );
exit( 1 );
}
/* add masterSocket to the master set */
FD_SET(masterSocket, &master);
/* track largest file descriptor, starting with masterSocket */
fdmax = masterSocket;
/* Wait for a client connection, then accept it. */
puts ( "Waiting for connection..." );
while(1){
temp_fds = master; /* copy master set to temp set */
//addrlen = sizeof(sin);
/* wait for activity on a socket */
if (select(fdmax+1, &temp_fds, NULL, NULL, NULL) == -1) {
perror("EchoServ select error");
exit(1);
}
for ( i = 0; i <= fdmax; i++ ){
printf("fd is %d\n", i); /*debug*/
if ( FD_ISSET( i, &temp_fds ) ){ /* true if file descriptor is in set */
/* accept new connection */
if ( i == masterSocket ){
addrlen = sizeof( sin );
if ( (newSocket = accept( masterSocket, ( struct sockaddr *) &sin, &addrlen )) == -1 )
perror("EchoServ: accept error");
else {
printf("New connection accepted\n"); /*debug*/
FD_SET( newSocket, &master ); /* add new connection to master set */
if ( newSocket > fdmax ) /* update max descriptor */
fdmax = newSocket;
//print details of new connection
printf("New connection on %s:%d, socket fd is %d \n",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), newSocket );
//send new connection greeting message
if( send( newSocket, message, strlen( message ), 0) == -1 )
{
perror("EchoServ welcome message error");
}
puts("Welcome message sent successfully");
}
}
}
/* handle incoming data */
else{
if ( ( nBytes = recv( i, buf, sizeof( buf ), 0 ) ) <= 0 ){ /* error or closed connection */
if ( nBytes == 0 ) /* connection closed */
printf( "EchoServ: socket %d closed by client\n", i );
else /* recv error */
perror("EchoServ recv error");
close( i ); /* close socket */
FD_CLR( i, &master ); /* remove from master set */
}
else { /* got some data */
for( j = 0; j <= fdmax; j++ ){
if ( FD_ISSET( j, &master ) ){ /* send data to all sockets */
if( j != i && j != masterSocket ){ /* except self and masterSocket */
if ( send( j, buf, nBytes, 0) == -1)
perror("EchoServ send error");
}
}
}
}
}
}
}
return( 0 );
}
Thanks for helping.
So you test if (FD_ISSET(i, &temp_fds)) and on the else branch you attempt to recv on i. So basically you're only trying to receive if i is invalid or would block.
This all of course stems from the unbounded use of blocks and braces. You probably meant that else to be paired with if (i == masterSocket).
I have a C program that I am trying to implement a daemon process that acts as a general TCP proxy server. I believe I have completed mostly everything correct but there is a while loop that I cannot figure out. Below is my code and I will put *** around what I am having trouble with.
Program descriptions
(1) The daemon listens for TCP connections on a specified port number.
(2) When a new client initiates a TCP connection request, the daemon accepts the request and
establishes a new TCP connection with the new client.
(a) The daemon forks a child process that is dedicated to handling the new client.
(b) The child process establishes a new TCP connection to a pre-assigned port on the actual
targeted server.
(c) The child process falls into a loop in which it acts as an intermediator exchanging data
(reading/writing or writing/reading) between the client and the targeted server.
(3) Once a child has been forked, the daemon process resumes listening for additional TCP
connections from other clients.
#ifndef unix
#define closesocket close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define PROTOPORT 5100 /* default protocol port number */
#define QLEN 6 /* size of request queue */
int visits = 0;
int argc;
char *argv[];
int main() // works as "server" side
{
struct hostent *ptrh; /* pointer to a host table entry */
struct protoent *ptrp; /* pointer to a protocol table entry */
struct sockaddr_in sad; /* structure to hold server's address */
struct sockaddr_in cad; /* structure to hold client's address */
int sd0, sd1; /* socket descriptors */
int port; /* protocol port number */
int addrlen; /* length of address */
pid_t pid;
memset((char *)&sad, 0, sizeof(sad)); /* clear sockaddr structure */
sad.sin_family = AF_INET; /* set family to Internet */
sad.sin_addr.s_addr = INADDR_ANY; /* set the local IP address(not specify, reserved */
if(argc > 1){
port = atoi(argv[1]);
}
else port = PROTOPORT; /* use the specified port number */
if (port > 0) /* test for illegal value */
sad.sin_port = htons((u_short)port);
else
{ /* print error message and exit */
fprintf(stderr,"bad port number %s\n", argv[1]);
exit(1);
}
/* Map TCP transport protocol name to protocol number */
if( ((int)(ptrp = getprotobyname("tcp"))) == 0) {
fprintf(stderr, "cannot map \"tcp\" to protocol number");
exit(1);
}
/* Create a socket */
sd0 = socket(PF_INET, SOCK_STREAM, ptrp->p_proto);
if(sd0 < 0){
fprintf(stderr, "socket creation failed\n");
exit(1);
}
/* Bind a local address to the socket */
// bind()
if (bind(sd0, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
fprintf(stderr,"bind failed\n");
exit(1);
}
/* Listen at the port */
// listen()
/* Specify size of request queue */
if (listen(sd0, QLEN) < 0) {
fprintf(stderr,"listen failed\n");
exit(1);
}
/* Main server loop - accept and handle requests */
while (1)
{
// accept request
addrlen = sizeof(cad);
sd1 = accept(sd0, (struct sockaddr *)&cad, &addrlen);
// fork a process
pid = fork();
if(pid == 0) // child process
{
//close oldsocket;
close(sd0);
HandleClientConnection(sd1);
break;
}
else /*parant process */
{
close(sd1);
continue;
}
}
return 0;
}
// implement "HandleClientConnection(new socket1)" - works as "client" side
HandleClientConnection(newsocket1)
{
// general socket settings at the client side
struct hostent *ptrh; /* pointer to a host table entry */
struct protoent *ptrp; /* pointer to a protocol table entry */
struct sockaddr_in sad; /* structure to hold an IP address */
int newsocket2; /* socket descriptor */
int port; /* protocol port number */
char *host; /* pointer to host name */
int n, n2; /* number of characters read */
char buf[1000]; /* buffer for data from the server */
int i;
memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
sad.sin_family = AF_INET; /* set family to Internet */
***while(1) /* get the real server's IP addr from "GET" command */
{
// read to buffer and compare, such as
if(strncmp("GET", buf[i-1], 3) == 0 || strncmp("CONNECT", buf[i-1], 7) == 0)
{
while(1)
{
//...; // read more
if(strncmp("Host", buf[i-1], 4) == 0)
{
//...;
printf("\nfound the host name.\n");
//...;
}
}
break;
}
}***
/* Convert real host name to equivalent IP address and copy to sad. */
// gethostbyname();
ptrh = gethostbyname(host);
if ( ((char *)ptrh) == NULL )
{
fprintf(stderr,"invalid host: %s\n", host);
exit(1);
}
memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
/* Map TCP transport protocol name to protocol number. */
if ( ((int)(ptrp = getprotobyname("tcp"))) == 0) {
fprintf(stderr, "cannot map \"tcp\" to protocol number");
exit(1);
}
/* Create a newsocket2. */
// socket();
newsocket2 = socket(PF_INET, SOCK_STREAM, ptrp->p_proto);
if (newsocket2 < 0) {
fprintf(stderr, "socket creation failed\n");
exit(1);
}
/* Connect the socket to the specified server. */
// connect()
if (connect(newsocket2, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
fprintf(stderr,"connect failed\n");
exit(1);
}
// Repeatedly read data from client (newsocket1) and write to server' side (newsocket2)
n = recv(newsocket1, buf, sizeof(buf), 0);
while (n > 0) {
write(newsocket2,buf,n);
n = recv(newsocket1, buf, sizeof(buf), 0);
}
// Repeatedly read data from server' side (newsocket2) and write to client (newsocket1).
n2 = recv(newsocket2, buf, sizeof(buf), 0);
while (n2 > 0) {
write(newsocket1,buf,n2);
n2 = recv(newsocket2, buf, sizeof(buf), 0);
}
// Close the newsocket2
close(newsocket2);
}