Im writing a program which connects to a browser and sends the http request from the browser to a server, and then sends the response back to the browser, which loads the page with some of the content. My program sends things successfully and loads pages, but does not run continuously and will crash after a random amount of time- sometimes 10 seconds of running sometimes 1 minute. I want this proxy to be able to run forever. Below is how I have structured my code. I have included the recv and write section which I think is causing my errors in full. I am pretty new to socket programming and c In general and looking for some tips on my structure and anything I may have missed.
int main(int argc, char *argv[])
{
char ip[40]
char *host = argv[1];
char *port_s = argv[2];
int err;
int socket_browser, socket_newBrowser, c;
struct sockaddr_in server, client;
int n;
socket_browser= socket(AF_INET, SOCK_STREAM, 0);
if (socket_browser < 0)
{
printf("Could not create socket");
}
if (err = bind(socket_browser , (struct sockaddr *)&server, sizeof(server)) != 0)
{
resourceError(err, "bind");
return 1;
}
if (err = listen(socket_browser , 3) != 0)
{
resourceError(err, "listen");
}
while (1){
c = sizeof(struct sockaddr_in);
server_socket= accept(socket_browser, (struct sockaddr *)&client, (socklen_t *)&c);
char buf[256];
int n;
n = recv(socket_newBrowser, buf, 256, 0);
if (n < 0){
resourceError(n,"recv");
}
int server_socket;
struct sockaddr_in server2;
server_socket= socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0)
{
resourceError(server_socket, "serverSocket");
}
server2.sin_addr.s_addr = inet_addr(ip);
server2.sin_family = AF_INET;
server2.sin_port = htons(80);
connect(server_socket, (struct sockaddr *)&server2, sizeof(server2))
send(server_socket, buf, strlen(buf), 0);
char reply[256];
int bytes_reply = 0;
do
{
bytes_reply = recv(server_socket, reply, sizeof(reply), 0);
// Need to check for double enter as this currently does not work in telnet
if (bytes_reply == -1)
{
perror("Recv error");
}
else
{
write(server_socket, reply, bytes_reply);
}
} while (bytes_reply > 0);
printf("connections closed");
}
return 0;
}
I think your problem (or at least a problem) is:
n = recv(socket_newBrowser, buf, 256, 0);
/*versus*/
send(server_socket, buf, strlen(buf), 0);
buf is not null-terminated, you should have used the n value returned from recv instead of strlen.
Related
I am building a client-server program in C using sockets. Both my client and my server use a fixed number of threads to operate. I tested with very few client and server threads at first (5 and 3) and everything seemed to work fine. But now I tried to up the number of client threads to 500 (while the number of server thread stays at 3), but everything breaks. The first hundred or so client can send their request and receive a response, but the others don't receive anything from the server.
I'm working on a Debian Windows Subsystem if that changes anything.
I have also tried upping the number of server thread to 300 but the problem still happens.
Here is my (very) simplified code.
Client thread
int client_socket= socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2018);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
connect(client_socket, (struct sockaddr *) &addr, sizeof(addr));
int response;
int cid = 1;
send(client_socket, &cid, sizeof(int), 0);
int len = read_socket(socket, &response, sizeof(int), 1000);
if (len == 0) {
printf("No response");
} else {
printf("Response");
}
close(client_socket);
Server thread
int socket_fd, cid, len;
while (1)
{
socket_fd =
accept(socket_fd, (struct sockaddr *)&thread_addr, &socket_len);
if (socket_fd> 0) {
int cid;
int len = read_socket(socket_fd, &cid, sizeof(cid), 1000);
if (len == 0) {
printf("Nothing");
}
send(socket_fd, &cid, sizeof(int),0);
close(socket_fd);
}
}
And here is my helper function read_socket()
ssize_t read_socket(int sockfd, void *buf, size_t obj_sz, int timeout) {
int ret;
int len = 0;
struct pollfd fds[1];
fds->fd = sockfd;
fds->events = POLLIN;
fds->revents = 0;
do {
// wait for data or timeout
ret = poll(fds, 1, timeout);
if (ret > 0) {
if (fds->revents & POLLIN) {
ret = recv(sockfd, (char*)buf + len, obj_sz - len, 0);
if (ret < 0) {
// abort connection
perror("recv()");
return -1;
}
len += ret;
}
} else {
// TCP error or timeout
if (ret < 0) {
perror("poll()");
}
break;
}
} while (ret != 0 && len < obj_sz);
return ret;
}
Like I said, some client can complete their execution with no problem, but a lot of them don't receive a response from the server.
I'm trying to write a simple UDP socket client-server program. The client machine is supposed to send a string to the server, that will answer with an ACK message.
Here's the implementation of the client side:
int main() {
message_send('L');
return EXIT_SUCCESS;
}
int message_send(char code) {
int sockfd;
ssize_t n;
char recvline[MAXLINE + 1];
struct sockaddr_in servaddr;
// Create an UDP socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
return -1;
}
// Setup the socket
memset((void *) &servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = (in_port_t) htonl(SERV_PORT);
if (inet_pton(AF_INET, SERVIP, &servaddr.sin_addr) <= 0) {
fprintf(stderr, "Error in inet_pton for %s\n", SERVIP);
exit(1);
}
// Send a test string
char *test = malloc(MAXLINE);
snprintf(test, MAXLINE, "SENDING:%c", code);
if (sendto(sockfd, &test, sizeof(test), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
perror("sendto");
return -1;
}
// Get an answer from the server
n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
if (n < 0) {
perror("recvfrom");
exit(1);
} else if (n > 0) {
recvline[n] = 0; // Add ending character
if (fputs(recvline, stdout) == EOF) { // Print the received message in stdout
perror("fputs");
return -1;
}
}
return 0;
}
If I run this (whether the server machine is running or not) I get the following error:
sendto: Invalid argument
Why am I getting this error?
The most likely cause of the problem is the line
servaddr.sin_port = (in_port_t) htonl(SERV_PORT);
I'm guessing that gives you a bad port number (i.e. it will give you port 0 on a little endian machine). Port numbers are 16-bit, so you should be using htons.
Also, passing &test and sizeof(test) to sendto will send the pointer value over the network. To send the string, you need to use test and strlen(test)+1.
I have two programs which communicate with each other.
Client: First send the message then listen for reply.
Server: Listen for reply and then send message.
Im able to send message from client prefectly and listen in server too. But problem comes when I try to send message from server.
struct hostent *gethostbyname();
typedef struct Message {
unsigned int length;
unsigned char data[SIZE];
} Message;
typedef struct sockaddr_in SocketAddress;
int fileDesc;
int aLength;
void main(int argc, char **argv) {
Message callMsg, rep;
aLength = 0;
SocketAddress clientSAMain, serverSAMain;
int port = RECIPIENT_PORT;
if ((fileDesc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
//return BAD;
}
makeReceiverSA(&serverSAMain, port);
if (bind(fileDesc, (struct sockaddr *) &serverSAMain,
sizeof(struct sockaddr_in)) != 0) {
perror("Bind failed\n");
close(fileDesc);
//return BAD;
}
clientSAMain.sin_family = AF_INET;
aLength = sizeof(serverSAMain);
GetRequest(&callMsg, port, &clientSAMain);
SendReply(&rep, port, clientSAMain);
close(fileDesc);
}
void GetRequest(Message *callMessage, int s, SocketAddress *clientSA) {
//SocketAddress serverSA;
int n;
int i;
if ((n = recvfrom(fileDesc, callMessage->data, SIZE, 0,
(struct sockaddr *) &clientSA, &aLength)) < 0)
perror("Receive 1");
else
printf("\n Received Message:(%s)length = %d \n", callMessage->data, n);
}
}
void SendReply(Message *replyMessage, int s, SocketAddress clientSANew) {
printf("Enter a reply:");
scanf("%s", replyMessage->data);
if ((n = sendto(fileDesc, replyMessage->data, sizeof(replyMessage->data), 0,
(struct sockaddr *) &clientSANew, sizeof(struct sockaddr_in))) < 0)
perror("Send Failed in Server\n");
if (n != strlen(replyMessage->data))
printf("sent %d\n", n + 1);
}
/* make a socket address using any of the addressses of this computer
for a local socket on given port */
void makeReceiverSA(struct sockaddr_in *sa, int port) {
sa->sin_family = AF_INET;
sa->sin_port = htons(port);
sa->sin_addr.s_addr = htonl(INADDR_ANY);
}
//If i place the sendreply function code in GetRequest function it is working fine. Can anyone help me with this. I have been trying all the possible way but did not find a solution. Work under progress for me so spare me if it is silly question.
PS:Edited out all the unnecessary code.
recvfrom(fileDesc, callMessage->data, SIZE, 0,
(struct sockaddr *) &clientSA, &aLength)
Because clientSA is a pointer, the above will overwrite the pointer variable and the memory after it. &clientSA in the above call should be clientSA.
I have a multi-client chat server and for some reason only the first client is being added. I used a tutorial to help get me started. I have included my code below. When I try and add another client it doesnt appear to be added. If I add one client I get a response from the server like I want but only the first message I enter then after that it stops sending correctly.
Server Code:
int main(void)
{
struct sockaddr_in my_addr, cli_addr[10],cli_temp;
int sockfd;
socklen_t slen[10],slen_temp;
slen_temp = sizeof(cli_temp);
char buf[BUFLEN];
int clients = 0;
int client_port[10];
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
{
printf("test\n");
err("socket");
}else{
printf("Server : Socket() successful\n");
}
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr* ) &my_addr, sizeof(my_addr))==-1)
{
err("bind");
}else{
printf("Server : bind() successful\n");
}
int num_clients = 0;
while(1)
{
//receive
printf("Receiving...\n");
if (recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&cli_temp, &slen_temp)==-1)
err("recvfrom()");
if (clients <= 10) {
cli_addr[clients] = cli_temp;
client_port[clients] = ntohs(cli_addr[clients].sin_port);
clients++;
printf("Client added\n");
//printf("%d",clients);
int i;
for(i=0;sizeof(clients);i++) {
sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&cli_addr[i], sizeof(cli_addr[i]));
}
}
}
close(sockfd);
return 0;
}
I have included the client code as well in case it helps.
void err(char *s)
{
perror(s);
exit(1);
}
sig_atomic_t child_exit_status;
void clean_up_child_process (int signal_number)
{
/* Clean up the child process. */
int status;
wait (&status);
/* Store its exit status in a global variable. */
child_exit_status = status;
}
int main(int argc, char** argv)
{
struct sockaddr_in serv_addr;
int sockfd, slen=sizeof(serv_addr);
char buf[BUFLEN];
struct sigaction sigchld_action;
memset (&sigchld_action, 0, sizeof (sigchld_action));
sigchld_action.sa_handler = &clean_up_child_process;
sigaction (SIGCHLD, &sigchld_action, NULL);
int pid,ppid;
if(argc != 2)
{
printf("Usage : %s <Server-IP>\n",argv[0]);
exit(0);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
err("socket");
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_aton(argv[1], &serv_addr.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
pid = fork();
if (pid<0) {
err("Fork Error");
}else if (pid==0) {
//child process will receive from server
while (1) {
bzero(buf,BUFLEN);
//printf("Attempting to READ to socket %d: ",sockfd);
fflush(stdout);
//recvfrom here
if (recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&serv_addr, &slen)==-1)
err("recvfrom()");
printf("The message from the server is: %s \n",buf);
if (strcmp(buf,"bye\n") == 0) {
ppid = getppid();
kill(ppid, SIGUSR2);
break;
}
}
}else {
//parent will send to server
while(1){
printf("Please enter the message to send: ");
bzero(buf,BUFLEN);
fgets(buf,BUFLEN,stdin);
printf("Attempting to write to socket %d: ",sockfd);
fflush(stdout);
//send to here
if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&serv_addr, slen)==-1)
{
err("sendto()");
}
}
}
close(sockfd);
return 0;
}
Several problems jump out at me. First, every time you receive a message it will consider that to be a new client. Instead of just incrementing the clients variable for a message, you'll need to scan through the array to see if the source address is already present. Second, sizeof(clients) will return a static value (probably 4) depending on how many bytes an int occupies on your machine. That loop should be for( int i = 0; i < clients; i++ ).
You also have a variable named num_clients which is not used. Is that supposed to be there for something and maybe is causing some confusion?
Finally, instead of using the magic value 10 all over the place, use #define MAX_CONNECTIONS 10 and then replace all those numbers with MAX_CONNECTIONS. It's a lot easier to read and change later.
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).