How do I delay my message by one second? UDP client - c

I'm making a program to send and receive messages over a network, I currently have it set up to repeat the message 50 times, but I'd like it to delay each message by one second. Is there a way I can do this using select? If not, how else can I do it?
Thanks.
Here's the code for my client
void
client (char * servername) {
ssize_t bytes;
int skt;
char buff[BUF_SIZE];
int i;
do{
skt = createsocket ( servername, PORT );
bytes = (ssize_t) sprintf (buff, "Hello %s, sequence number:", servername);
if (write (skt, buff, bytes) < bytes) {
fprintf (stderr, "WARNING: write didn't accept complete message\n");
}
memset (buff, 0, BUF_SIZE);
bytes = read (skt, buff, BUF_SIZE);
if (bytes < 0) {
perror ("read()");
exit (1);
}
printf ("Server echoed the following: %s\n", buff);
i++;
}while(i < 50);
}
P.s. I'm also going to try to add a sequence number in there using a long type, how would I go about this?

This should be reasonably close to what you want. (Did not test.)
void client (char * servername)
{
ssize_t bytes;
int skt;
char buff[BUF_SIZE];
int i = 0;
long seqNum = 0;
skt = createsocket ( servername, PORT );
do
{
memset (buff, 0, BUF_SIZE);
struct timeval t = {1, 0};
select(0, NULL, NULL, NULL, &t);
bytes = (ssize_t) sprintf (buff, "Hello %s, sequence number: %ld", servername, seqNum++);
if (write (skt, buff, bytes) < bytes)
{
fprintf (stderr, "WARNING: write didn't accept complete message\n");
}
memset (buff, 0, BUF_SIZE);
bytes = read (skt, buff, BUF_SIZE);
if (bytes < 0)
{
perror ("read()");
exit (1);
}
printf ("Server echoed the following: %s\n", buff);
i++;
}
while (i < 50);
}

Related

IRC client does not print/receive full response

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
static char *host = "irc.libera.chat";
static char *port = "6667";
static char *chan = "#libera";
static char *nick = "nick";
static char *pass = NULL;
static int sock = 0;
void
message(char *fmt, ...) {
va_list ap;
/* determine size */
va_start(ap, fmt);
int n = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (n < 0) {
fputs("vsnprintf() failed", stderr);
exit(EXIT_FAILURE);
}
size_t size = n + 1;
/* construct */
char *msg = malloc(size);
if (msg == NULL) {
perror("malloc() failed");
exit(EXIT_FAILURE);
}
va_start(ap, fmt);
n = vsnprintf(msg, size, fmt, ap);
va_end(ap);
if (n < 0) {
fputs("vsnprintf() failed\n", stderr);
free(msg);
exit(EXIT_FAILURE);
}
/* send */
ssize_t nsent = send(sock, msg, size, 0);
free(msg);
if (nsent == -1) {
perror("send() failed");
exit(EXIT_FAILURE);
} else if ((size_t)nsent != size) {
fprintf(stderr,
"send() failed: expected to send %lu bytes, sent %ld instead\n",
size, nsent);
exit(EXIT_FAILURE);
}
}
int
main(void) {
/* initialize connection */
struct addrinfo hints = {
.ai_flags = 0,
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = 0,
.ai_addrlen = 0,
.ai_addr = NULL,
.ai_canonname = NULL,
.ai_next = NULL
};
struct addrinfo *res;
int ret = getaddrinfo(host, port, &hints, &res);
if (ret != 0) {
fprintf(stderr, "getaddrinfo() failed: %s\n", gai_strerror(ret));
return EXIT_FAILURE;
}
struct addrinfo *rp;
for (rp = res; rp != NULL; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock == -1) {
perror("socket() failed");
continue;
}
if (connect(sock, rp->ai_addr, rp->ai_addrlen) == -1) {
perror("connect() failed");
close(sock);
continue;
}
break;
}
freeaddrinfo(res);
if (rp == NULL) {
fprintf(stderr, "could not connect to %s:%s\n", host, port);
return EXIT_FAILURE;
}
/* log in */
if (pass)
message("PASS %s\n", pass);
message("NICK %s\n", nick);
message("USER %s - - :%s\n", nick, nick);
/* join channel */
if (chan != NULL)
message("JOIN %s\n", chan);
/* print response */
char buffer[4096];
ssize_t nbyte;
loop:
nbyte = recv(sock, buffer, 4095, 0);
if (nbyte < 0) {
fputs("recv() failed", stderr);
return 1;
} else if (nbyte == 0) {
fputs("recv() failed: connection closed prematurely", stderr);
return 1;
}
buffer[nbyte] = '\0';
printf("%s", buffer);
goto loop;
/* unreachable */
}
outputs
:calcium.libera.chat NOTICE * :*** Checking Ident
:calcium.libera.chat NOTICE * :*** Looking up your hostname...
:calcium.libera.chat NOTICE * :*** Couldn't look up your hostname
:calcium.libera.chat NOTICE * :*** No Ident response
ERROR :Closing Link: 127.0.0.1 (Connection timed out)
recv() failed: connection closed prematurely
Why am I not receiving the proper response?
Other irc clients further output
:calcium.libera.chat 001 nick :Welcome to the Libera.Chat Internet Relay Chat Network nick
...
Could the issue be in error handling?
For example, according to send(2)
On success, these calls return the number of bytes sent. On error, -1 is returned, and errno is set to indicate the error.
so
} else if ((size_t)nsent != size) {
fprintf(stderr,
"send() failed: expected to send %lu bytes, sent %ld instead\n",
size, nsent);
exit(EXIT_FAILURE);
}
seems redundant, as well as its recv counterpart.
Am I handling vsnprintf and malloc correctly?
When you trace the application (E.g. using strace) you will see the following calls:
connect(3, {sa_family=AF_INET, sin_port=htons(6667), sin_addr=inet_addr("172.106.11.86")}, 16) = 0
sendto(3, "NICK nick\n\0", 11, 0, NULL, 0) = 11
sendto(3, "USER nick - - :nick\n\0", 21, 0, NULL, 0) = 21
sendto(3, "JOIN #libera\n\0", 14, 0, NULL, 0) = 14
Meaning when sending the NICK, USER and JOIN, those strings are begin transmitted with an additional null byte at the end and the server on the other side doesn't like that.
This implies that in your code the message() method is wrong, more specifically the calculation of the size variable. If I compile your code with size decremented before the send() call, the connection to the irc server succeeds.
You are handling vsnprintf() and malloc() fine. It is send() that you are not handling correctly. There are two problems with your usage:
you are including the formatted string's null-terminator in the transmission. Don't do that, that is not part of the IRC protocol.
you are not accounting for partial transmissions, as send() can return fewer bytes than requested, thus requiring send() to be called again to send any unsent bytes. So you need to call send() in a loop. A return value that is greater than 0 but less than the number of requested bytes is not an error condition. The only error condition is a return value that is less than 0.
Try this instead:
void
message(char *fmt, ...) {
va_list ap;
/* determine size */
va_start(ap, fmt);
int n = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (n < 0) {
fputs("vsnprintf() failed", stderr);
exit(EXIT_FAILURE);
}
size_t size = n + 1;
/* construct */
char *msg = malloc(size);
if (msg == NULL) {
perror("malloc() failed");
exit(EXIT_FAILURE);
}
va_start(ap, fmt);
n = vsnprintf(msg, size, fmt, ap);
va_end(ap);
if (n < 0) {
fputs("vsnprintf() failed\n", stderr);
free(msg);
exit(EXIT_FAILURE);
}
/* send */
char *curr = msg;
--size; // don't sent null terminator!
while (size > 0) {
ssize_t nsent = send(sock, curr, size, 0);
if (nsent < 0) {
perror("send() failed");
free(msg);
exit(EXIT_FAILURE);
}
curr += nsent;
size -= nsent;
}
free(msg);
}
That said, you really shouldn't be using a goto loop in main(), either. Use a while or do..while loop instead, eg:
int
main(void) {
...
/* print response */
char buffer[4096];
int exitCode = 0;
do {
ssize_t nbyte = recv(sock, buffer, sizeof buffer, 0);
if (nbyte < 0) {
perror("recv() failed");
exitCode = 1;
} else if (nbyte == 0) {
fputs("connection closed by peer", stderr);
exitCode = 1;
} else {
printf("%.*s", nbyte, buffer);
}
}
while (exitCode == 0);
close(sock);
return exitCode;
}

How can I stop the while?

I have A TCP Server-Client where I enter a number with the number of times that I want to send the word to the server. So I send correctly because I print the information on a loop(in client) but in the server shows infinitely because I put while(1) but if I don't use just print it one time. I don't want to send the number to the server.
If I enter the number 4 I want to print the word "hello" four times
This is the server, now it's printing infinitely obviously.
#define MAXPENDING 5 /* Maximum number of simultaneous connections */
#define BUFFSIZE 255 /* Size of message to be received */
void err_sys(char *mess) { perror(mess); exit(1); }
void handle_client(int sock) {
char buffer[BUFFSIZE];
int received = -1;
while (1) {
/* Read from socket */
read(sock, &buffer[0], BUFFSIZE);
printf("Message from client: %s\n", buffer);
/* Write to socket */
write(sock, buffer, strlen(buffer) + 1);
/* Close socket */
close(sock);
}
}
int main(int argc, char *argv[]) {
struct sockaddr_in echoserver, echoclient;
int serversock, clientsock;
int result;
/* Check input arguments */
if (argc != 2) {
fprintf(stderr, "Usage: %s <port>\n", argv[0]);
exit(1);
}
/* Create TCP socket */
serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serversock < 0) {
err_sys("Error socket");
}
/* Set information for sockaddr_in structure */
memset(&echoserver, 0, sizeof(echoserver)); /* we reset memory */
echoserver.sin_family = AF_INET; /* Internet/IP */
echoserver.sin_addr.s_addr = htonl(INADDR_ANY); /* ANY address */
echoserver.sin_port = htons(atoi(argv[1])); /* server port */
/* Bind socket */
result = bind(serversock, (struct sockaddr *) &echoserver, sizeof(echoserver));
if (result < 0) {
err_sys("Error bind");
}
/* Listen socket */
result = listen(serversock, MAXPENDING);
if (result < 0) {
err_sys("Error listen");
}
while (1) {
unsigned int clientlen = sizeof(echoclient);
/* Wait for a connection from a client */
clientsock = accept(serversock, (struct sockaddr *) &echoclient, &clientlen);
if (clientsock < 0) {
err_sys("Error accept");
}
fprintf(stdout, "Client: %s\n", inet_ntoa(echoclient.sin_addr));
/* Call function to handle socket */
handle_client(clientsock);
}
}
This is the client
printf("Enter a number between 0 to 9[0 to exit]: ");
fgets(number, 100, stdin);
while(strtol(number,&pEnd,10)!=0){
while (!((strtol(number,&pEnd,10) <= 9) && (strtol(number,&pEnd,10) >= 0))) {
printf("[ERROR] The number you entered is out of range\n");
printf("Enter a number between 0 to 9[0 to exit]: ");
fgets(number, 100, stdin);
}
if(strtol(number,&pEnd,10)!=0){
printf("Enter a word: ");
fgets(buffer, 100, stdin);
for(int i=0;i<strtol(number,&pEnd,10);i++){
write(sock, buffer, strlen(buffer) + 1);
fprintf(stdout, " sent \n");
read(sock, buffer, BUFFSIZE);
fprintf(stdout, " %s ...done \n", buffer);
}
}
printf(" Enter a number between 0 to 9[0 to exit]: ");
fgets(number, 100, stdin);
}
There are multiple problems in you code:
you do not test if read() succeeds. You should break from the loop if it fails.
you unconditionally close the socket in the body of the loop: the next read will fail and return -1 immediately, you will print a bogus message and iterate at nauseam.
you call strlen() and printf() with a buffer that might not be null terminated, potentially causing undefined behavior.
Here is a modified version:
void handle_client(int sock) {
char buffer[BUFFSIZE];
int received = -1;
if (sock < 0)
return;
for (;;) {
/* Read from socket */
received = read(sock, buffer, sizeof(buffer) - 1);
if (received <= 0)
break;
buffer[received] = '\0';
printf("Message from client: %s\n", buffer);
/* Write to socket */
write(sock, buffer, received);
}
/* Close socket */
close(sock);
}
You have an infinite loop in your hands normally that is not recommended but if you need to do it then add a if statement such:
while(1){
if(clientsock < 0){/*statement that is met so that your code stops running the if */
break;
}
}

c - client server socket programming - sending files

I am having trouble sending and receiving files while working with sockets in C.
Let's say I have a file that is 2,463 bytes big and I want to send it from client to server but it never sends the entire file.
I've been searching the internet for a while now but couldn't find a solution so I'd be very glad if someone could tell me how to make this work.
Here is my code:
Client:
char buffer[256];
bzero(buffer, 256);
int block_size;
while(1){
block_size = fread(buffer, sizeof(char), sizeof(buffer), fs); // read from the file
if (block_size == 0){
break;
}
if (block_size < 0){
perror("ERROR: Failed while sending data.");
exit(EXIT_FAILURE);
break;
}
void *p = buffer;
while (block_size > 0) {
int bytes_written = write(clientSocket, buffer, block_size); // send the data to server
if (bytes_written <= 0) {
perror("ERROR: Failed while sending data.");
exit(EXIT_FAILURE);
}
block_size -= bytes_written;
p += bytes_written;
}
bzero(buffer, 256);
}
Server:
bzero(buffer, 256);
int file_block_size = 0;
while (1){
bzero(buffer, 256);
file_block_size = read(incoming_socket, buffer,255); // read the data from client
fwrite(buffer, sizeof(char), file_block_size, fr); // write the data to file
if (file_block_size == 0 || file_block_size < 256){
fwrite(buffer, sizeof(char), file_block_size, fr);
break;
}
}
As I've said, this never sends the entire file that is for example 2,463 bytes big, only a portion of it.
Thanks in advance, will be glad for any help I can get.
You need to pair your read with a write. As in the current state your client code will send only the result of your last read operation since you are overwriting the contents of your buffer on each read.
Try something like this on the client side:
char buffer[256];
size_t bytes_read = 0;
ssize_t bytes_written = 0;
do{
bytes_read = fread(buffer, sizeof(char), sizeof(buffer), fs);
if(ferror(fs))
{
perror("Error while reading from file.");
close(clientSocket);
fclose(fs);
exit(EXIT_FAILURE);
}
bytes_written = write(clientSocket, buffer, bytes_read);
printf("Write operation status: %s; bytes sent: %d\n", strerror(errno), bytes_written);
} while(!feof(fs) && bytes_written != -1);
And on the server side I would do:
char buffer[256];
ssize_t bytes_read = 0;
while((bytes_read = read(incoming_socket, buffer, sizeof(buffer))) > 0)
{
printf("%d bytes read\n", bytes_read);
fwrite(buffer, sizeof(char), bytes_read, fr);
if(ferror(fr))
{
perror("Error while writing to file");
close(incoming_socket);
fclose(fr);
exit(EXIT_FAILURE);
}
}
if(bytes_read == -1)
printf("%s\n", strerror(errno));

RECV buffer empty, but returns a value > 1

I am attempting to make a simple server so that two clients can communicate with each other. The main server code accepts the two client connections and then forks off a process that uses execl to generate a personal server between the two clients so that the main server can continue looking for new connections. Everything seems to work correctly until the personal server attempts to contact the clients and they both receive gibberish, if anyone knows what could cause this please let me know.
Main server after accepting two clients:
if(fork() == 0){
close(listener);
int nBytes;
char* playerOne[20];
char* playerTwo[20];
//Creates strings to hold file descriptor information for execl
char connAscii[sizeof(int)];
char connAscii2[sizeof(int)];
snprintf(connAscii,sizeof(conn), "%d", conn);
snprintf(connAscii2,sizeof(conn2), "%d", conn2);
fprintf(stderr, "Int conn: %d, asciiConn: %s, backToInt: %d\n", conn, connAscii, atoi(connAscii));
char *argf[2];
argf[0] = connAscii;
argf[1] = connAscii2;
fprintf(stderr, "that is to say %s and %s\n", argf[0], argf[1]);
//Send Handle Request to Connection 1
nBytes = send(conn, handleRequest, sizeof(handleRequest),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Receive Handle from Connection 1
nBytes = recv(conn, playerOne, 20, 0);
if(nBytes == -1){
perror("recv");
exit(1);
}
//Send Handle Request to Connection 2
nBytes = send(conn2, handleRequest, sizeof(handleRequest),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Receive Handle from Connection 2
nBytes = recv(conn2, playerTwo, 20, 0);
if(nBytes == -1){
perror("recv");
exit(1);
}
//Send Handle for Connection 2 to Connection 1
nBytes = send(conn, playerTwo, sizeof(playerTwo),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Send Handle for Connection 1 to Connection 2
nBytes = send(conn2, playerOne, sizeof(playerOne),0);
if(nBytes == -1){
perror("send");
exit(1);
}
//Passes file descriptors to privateServer
execl("privateServer","privateServer", connAscii, connAscii2, (char *)0);
}
Personal server invoked by execl:
char greet[] = {"Hello players, please wait for match setup."};
int main(int argc, char *argv[]) {
int conn1 = atoi(argv[1]);
int conn2 = atoi(argv[2]);
int sent;
fprintf(stderr, "Attempting connection with %d\n", conn1);
sent = send(conn1, greet,sizeof(greet),0);
if(sent == -1){
perror("send");
exit(1);
}
sent = send(conn2, greet,sizeof(greet),0);
if(sent == -1){
perror("send");
exit(1);
}
fprintf(stderr,"Hopefully they got it\n");
return 0;
}
Clients: Reading the recv buff char by char results in gibberish and printing the entire buffer doesn't show anything, but numbytes == 61.
char *buff = (char*)malloc(100);
memset(&buff[0],0,sizeof(buff));
numbytes = recv(sockfd, buff, 99, 0); //should be from private server
if (numbytes == -1) {
perror("recv");
exit(1);
}
buff[numbytes] = '\0';
int i;
for(i = 0; i < numbytes; i++){
fprintf(stderr, "%c", buff[i]);
}
printf("From match server: %.*s (%d bytes)\n", numbytes, buff, numbytes);
There are several errors:
char* playerOne[20];
char* playerTwo[20];
You want an array of chars, not an array of pointers to chars
change to
char playerOne[20];
char playerTwo[20];
And here:
char *buff = (char*)malloc(100);
memset(&buff[0],0,sizeof(buff));
sizeof(buff) is the size of a pointer to char, change to
memset(&buff[0],0,100);
As pointed out by #user3629249, don't use magic numbers like 100, instead
#define MAX_BUFF 100
char *buff = malloc(MAX_BUFF);
memset(&buff[0],0,MAX_BUFF);
But there is no need to memset if you are null-terminating the string.

C socket, send message after file, TCP

I want to send file through socket and after that i want to send three messages. This code below works, but i have to send first sentence two times. My question is why? Without one sentence1, receiver display sentence2, sentence3 and sentence3. What is wrong with this code?
I'm using tcp protocol.
Sender.c
char file_size[256];
struct stat file_stat;
int sent_bytes = 0;
int fd;
int offset;
int remain_data;
fd = open(FILE_TO_SEND, O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Error opening file --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Get file stats */
if (fstat(fd, &file_stat) < 0)
{
fprintf(stderr, "Error fstat --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "File Size: \n%d bytes\n", file_stat.st_size);
sprintf(file_size, "%d", file_stat.st_size);
write(sck, file_size, 256);
char buffer[1024] = "";
while (1) {
int bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read == 0)
break;
void *p = buffer;
while (bytes_read > 0) {
int bytes_written = write(sck, p, bytes_read);
if (bytes_written <= 0) {
// handle errors
}
bytes_read -= bytes_written;
p += bytes_written;
}
}
char sentence[1024];
write(sck, sentence1, 1024);
write(sck, sentence1, 1024);
write(sck, sentence2, 1024);
write(sck, sentence3, 1024);
Receiver.c
char buffer[1024] = "";
int sck = *((int*) arg);
int file_size;
read(sck, buffer, 256);
file_size = atoi(buffer);
ssize_t len;
FILE *received_file;
int remain_data = 0;
received_file = fopen("plik.pdf", "w");
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
while (((len = recv(sck, buffer, 1024, 0)) > 0) && (remain_data > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
remain_data -= len;
}
fclose(received_file);
read (sck, buffer, 1024);
printf("%s 1\n", buffer);
read (sck, buffer, 1024);
printf("%s 2\n", buffer);
read (sck, buffer, 1024);
printf("%s 3\n", buffer);
Nothing to do with TCP protocol. Your logic is flawed. You are receiving the data and then checking for remain_data. So your sentence1 is received and discarded in the while loop.
Move your recv() into the body of while to fix this or change the order in while.
while ((remain_data > 0) && ((len = recv(sck, buffer, 1024, 0)) > 0))
In the modified while, you call recv() only if remain_data > 0. recv() is not called if remain_data == 0 (lazy evaluation). So your while loop ends immediately after receiving the file and ready to receive your sentences. In your code, the while loop read the first sentence, then checked remain_data > 0 effectively discarding sentence1

Resources