I am trying to implement an 'internet radio' in C. This requires a server that keeps on playing an audio file continuously and whenever a client request arrives, the server creates a thread that delivers the audio file to the user. The server , when started, spawns a thread that keeps on writing from an audio file onto a global buffer space and the user corresponding buffers keep on reading from the global buffer space and keep on sending the audio file in 'chunks' to the user. And the user tries to play the audio file through the help of '/dev/audio' (I am using ubuntu).
The problem is that when I try to open a '.au' file using 'open' function on the server, a file descriptor of 0 is assigned. So, I am unable to pull the contents out of the audio file and send it to the client(Rather whatever I type on the terminal is sent to the client).
Is there some way of open '.au' files with the 'open' function in C?? If not, then what file extensions does 'open' function support and what can I do, i.e., what type of file extension should I use to make the 'open' function open the file and send to the user?
assure you are using open file mode of binary - IE. given_mode = "rb" where r means read and b means binary - following code reads a binary file and outputs the first few bytes - enjoy
// gcc -o read_binary_au_file read_binary_au_file.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main() {
const char * given_mode = "rb";
const char * given_filename = "/home/scott/Documents/data/audio/sample.au";
FILE * fh;
fh = fopen(given_filename, given_mode);
if (fh == NULL) {
fprintf(stderr, "ERROR - failed to open file %s in mode %s\n",
given_filename, given_mode);
return (-2);
}
// --- identify file size --- //
off_t file_size;
struct stat stat_struct; // data structure to be returned from call to fstat on file descriptor
int fd = fileno(fh); // get file descriptor from file handle
if ((fstat(fd, & stat_struct) != 0) || (! S_ISREG(stat_struct.st_mode))) {
fprintf(stderr, "ERROR - failed to stat file");
return (-3);
}
file_size = stat_struct.st_size;
printf("file_size %lu\n", file_size);
// --- now read data from the binary file --- //
unsigned long MAX_READ_CHARS = 4096;
unsigned long desired_num_bytes_to_read = (file_size > MAX_READ_CHARS) ? MAX_READ_CHARS : file_size;
char * mem_buffer = malloc(sizeof(char) * desired_num_bytes_to_read);
unsigned long num_bytes_actually_io = 0;
// read initial bytes into memory buffer
num_bytes_actually_io = fread(mem_buffer, sizeof(char), desired_num_bytes_to_read, fh);
if (fclose(fh)) {
fprintf(stderr, "ERROR - failed to close file\n");
return (-4);
}
if (num_bytes_actually_io != desired_num_bytes_to_read) {
fprintf(stderr, "ERROR - failed to read desired_num_bytes_to_read %lu ... instead num_bytes_actually_io %lu\n",
desired_num_bytes_to_read, num_bytes_actually_io);
return (-1);
}
printf("num_bytes_actually_io %lu\n", num_bytes_actually_io);
// ... now do something with mem_buffer which contains data read from binary file
int num_bytes_to_show = 100;
num_bytes_to_show = (num_bytes_actually_io > num_bytes_to_show) ? num_bytes_to_show : num_bytes_actually_io;
printf("\nhere are the first %d characters from given binary file\n", num_bytes_to_show);
printf("-->");
int i = 0;
for (; i < num_bytes_to_show; i++) {
// printf("%c", mem_buffer[i]); // as chars
printf("%x", mem_buffer[i]); // as hex
}
printf("<--");
printf("\n");
free(mem_buffer);
printf("\nprocessing complete\n");
return 0;
}
Related
I am attempting to read a '.raw' file which stores the contents of an image that was taken on a camera using C. I would like to store these contents into a uint16_t *.
In the following code I attempt to store this data into a pointer, using fread(), and then write this data into a test file, using fwrite(), to check if my data was correct.
However, when I write the file back it is completely black when I check it.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define MAX_ROW 2560
#define MAX_COL 2160
int main()
{
char filename[32] = "image1.raw";
FILE * image_raw = fopen(filename, "rb");
fseek(image_raw, 0, 2);
long filesize = ftell(image_raw);
/*READ IMAGE DATA*/
uint16_t * image_data_ptr;
image_data_ptr = (uint16_t *)malloc(sizeof(uint16_t)*MAX_ROW*MAX_COL);
fread(image_data_ptr, sizeof(uint16_t), filesize, image_raw);
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp;
fp = fopen("TEST.raw", "w");
fwrite(image_data_ptr, sizeof(uint16_t), filesize, fp);
fclose(fp);
return 0;
}
There are multiple issues with your code:
lack of error handling.
not seeking the input file back to offset 0 after seeking it to get its size. Consider using stat() or equivalent to get the file size without having to seek the file at all.
not dividing filesize by sizeof(uint16_t) when reading from the input file, or writing to the output file. filesize is expressed in bytes, but fread/fwrite are expressed in number of items of a given size instead, and your items are not 1 byte in size.
not opening the output file in binary mode.
leaking the buffer you allocate.
With that said, try something more like this instead:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main()
{
char filename[32] = "image1.raw";
FILE *image_raw = fopen(filename, "rb");
if (!image_raw) {
fprintf(stderr, "Can't open input file\n");
return -1;
}
if (fseek(image_raw, 0, SEEK_END) != 0) {
fprintf(stderr, "Can't seek input file\n");
fclose(image_raw);
return -1;
}
long filesize = ftell(image_raw);
if (filesize == -1L) {
fprintf(stderr, "Can't get input file size\n");
fclose(image_raw);
return -1;
}
rewind(image_raw);
long numSamples = filesize / sizeof(uint16_t);
/*READ IMAGE DATA*/
uint16_t *image_data_ptr = (uint16_t*) malloc(filesize);
if (!image_data_ptr) {
fprintf(stderr, "Can't allocate memory\n");
fclose(image_raw);
return -1;
}
size_t numRead = fread(image_data_ptr, sizeof(uint16_t), numSamples, image_raw);
if (numRead != numSamples) {
fprintf(stderr, "Can't read samples from file\n");
free(image_data_ptr);
fclose(image_raw);
return -1;
}
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp = fopen("TEST.raw", "wb");
if (!fp) {
fprintf(stderr, "Can't open output file\n");
free(image_data_ptr);
return -1;
}
if (fwrite(image_data_ptr, sizeof(uint16_t), numSamples, fp) != numSamples) {
fprintf(stderr, "Can't write to output file\n");
fclose(fp);
free(image_data_ptr);
return -1;
}
fclose(fp);
free(image_data_ptr);
return 0;
}
You have already a great answer and useful comments
anyway, consider that if you want to iterate over your file, loaded in memory as a whole, as an array of unsigned words:
if the file size could be odd what to do at the last byte/word
you may read the file as a whole in a single call, after having the file size determined
fstat() is the normal way to get the file size
get the file name from the command line as an argument is much more flexible than recompile the program or change the file name in order to use the program
The code below does just that:
uses image.raw as a default for the file name, but allowing you to enter the file name on the command line
uses fstat() to get the file size
uses a single fread() call to read the entire file as a single record
A test using the original program file as input:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 20/07/2021 17:40 1067 main.c
PS > gcc -Wall -o tst main.c
PS > ./tst main.c
File is "main.c". Size is 1067 bytes
File "main.c" loaded in memory.
PS > ./tst xys
File is "xys". Could not open: No such file or directory
The C example
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char**argv)
{
const char* default_file = "image.raw";
char f_name[256];
if (argc < 2)
strcpy(f_name, default_file);
else
strcpy(f_name, argv[1]);
FILE* F = fopen(f_name, "rb");
if (F == NULL)
{
printf("File is \"%s\". ", f_name);
perror("Could not open");
return -1;
}
struct stat info;
fstat(_fileno(F),&info);
printf("File is \"%s\". Size is %lu bytes\n", f_name, info.st_size);
uint16_t* image = malloc(info.st_size);
if (image == NULL)
{ perror("malloc() error");
return -2;
};
if (fread(image, info.st_size, 1, F) != 1)
{ perror("read error");
free(image);
return -3;
};
// use 'image'
printf("File \"%s\" loaded in memory.\n", f_name);
free(image);
fclose(F);
return 0;
}
I am working on a program in C that involves client-server connections and communication between the two parties.
The program involves the client sending a letter to the server and the server getting the letter. The server then searches through the current file directory (in linux) for a file beginning with that letter and sends the client the number of bytes of the file and the text of the file.
The overall program is very long and for the assignment the instructor already did much of the code such as setting up the sockets and creating the entire program for the client side of operations.
For the server side I had to write code for:
getting the file descriptor from the passed memory and casting it
-getting the letter from the client
-Attempting to open the current directory
-Iterating through the directory looking for a file that starts with the letter
-Attempting to open the file and sending the size of the file and number of bytes of file to the client in network endian
-Closing the file and directory after finishing
-Error checking: there are error checking statements if the directory cannot be opened, the file cannot be opened, or no matching file is found
The following is my code with comments
void* handleClient (void* vPtr
)
{
// I. Application validity check:
int fd = *((int *) vPtr);
//casting vPtr to an int//
free(vPtr);
// II. Handle the client:
char buffer[BUFFER_LEN+1];
read(fd, buffer, BUFFER_LEN+1);
//read the letter into a buffer//
const char* dirNamePtr = ".";
DIR* dirPtr = opendir(dirNamePtr);
// Open the current directory
if (dirPtr == NULL)
{
int toSend = htonl(CANT_READ_DIR_CODE);
write(fd,&toSend,sizeof(toSend));
printf("Cannot read directory\n");
return(NULL);
}
// If current directory cannot be opened, it sends a error message in network // endian to the client
struct dirent* entryPtr;
char path[BUFFER_LEN];
struct stat statBuffer;
//implements struct dirent to get info on the directory
//iterates through the directory
while ((entryPtr=readdir(dirPtr)) != NULL)
{
stat(entryPtr->d_name, &statBuffer);
//puts in metaddata of the current directory into statbuffer
if (!S_ISREG(statBuffer.st_mode))
continue;
//if the entry is not a file, continue
// if the first letter of the file is not the character received from the //client, send an error mesage
if(entryPtr->d_name[0]!=buffer[0]) {
int toSend2 = htonl(NO_MATCH_CODE);
write(fd,&toSend2,sizeof(toSend2));
printf("No matching file\n");
return(NULL);
}
int ab;
int numRead;
int numBytes;
char buffer[BUFFER_LEN];
//open the file and send bytes of file and file size to client
if (entryPtr->d_name[0]==buffer[0] &(S_ISREG(statBuffer.st_mode)))
{
ab=open(entryPtr->d_name,O_RDONLY,0660);
if(ab<0) {
int toSend3 = htonl(CANT_READ_FILE_CODE);
write(fd,&toSend3, sizeof(toSend3));
printf("Cannot read <filename>\n");
return(NULL);
}
numBytes=htonl(statBuffer.st_size);
write(fd, &numBytes, sizeof(numBytes));
printf("Sending %s, %d bytes\n",entryPtr >d_name,statBuffer.st_size);
while((numBytes=read(ab,buffer,BUFFER_LEN))>0)
{
printf("We read %d bytes\n", numBytes);
write(fd, buffer, numBytes);
}
//close the fiel
close(ab);
}
break;
//leave the loop
}
// III. Finished:
//
closedir(dirPtr);
return(NULL);
}
My code compiles but does not send the file to the client when I try running it. I have tried several different letters and it has not worked for any of them. I do not quite know what the issue is which makes it difficult to fix my mistakes.
I am not asking for the answer or anything, just help in seeing where I am wrong. I appreciate any help.
Your logic for when to send vs. when to send no-file status seems wrong. I think it should be like this (fair warning, I didn't test this, or even compile it beyond basic syntax checking, but you should get the idea):
void* handleClient(void* vPtr)
{
// I. Application validity check:
int fd = *((int *) vPtr);
free(vPtr);
// II. Handle the client:
char buffer[BUFFER_LEN+1];
read(fd, buffer, BUFFER_LEN+1);
//read the letter into a buffer//
const char* dirNamePtr = ".";
DIR* dirPtr = opendir(dirNamePtr);
// Open the current directory
if (dirPtr == NULL)
{
int toSend = htonl(CANT_READ_DIR_CODE);
write(fd,&toSend,sizeof(toSend));
printf("Cannot read directory\n");
return(NULL);
}
struct dirent* entryPtr;
char path[BUFFER_LEN];
struct stat statBuffer;
//implements struct dirent to get info on the directory
//iterates through the directory
while ((entryPtr=readdir(dirPtr)) != NULL)
{
stat(entryPtr->d_name, &statBuffer);
//puts in metaddata of the current directory into statbuffer
// if this isn't a regular file OR the first char doesn't match...
if (!S_ISREG(statBuffer.st_mode) || entryPtr->d_name[0]!=buffer[0])
continue;
int ab;
int numRead;
int numBytes;
char buffer[BUFFER_LEN];
//open the file and send bytes of file and file size to client
ab = open(entryPtr->d_name,O_RDONLY,0660);
if(ab<0) {
int toSend3 = htonl(CANT_READ_FILE_CODE);
write(fd,&toSend3, sizeof(toSend3));
printf("Cannot read <filename>\n");
closedir(dirPtr);
return(NULL);
}
numBytes=htonl(statBuffer.st_size);
write(fd, &numBytes, sizeof(numBytes));
printf("Sending %s, %d bytes\n",entryPtr >d_name,statBuffer.st_size);
while((numBytes=read(ab,buffer,BUFFER_LEN))>0)
{
printf("We read %d bytes\n", numBytes);
write(fd, buffer, numBytes);
}
//close the file and leave
close(ab);
break;
}
// if this is NULL it means we dind't send anything. we break the loop
// when a file to send it discovered.
if (entryPtr == NULL)
{
printf("No matching file\n");
int toSend2 = htonl(NO_MATCH_CODE);
write(fd, &toSend2, sizeof(toSend2));
}
// III. Finished:
closedir(dirPtr);
return(NULL);
}
I am using C file IO to read value from a sysfs interface in linux. Path and sample value of the register is as follows:
cat /sys/class/powercap/intel-rapl/intel-rapl\:0/energy_uj
56039694184
Code: Added \ after intel-rapl\ to take into account unknown escape sequence
#define FILE_SIZE 512
static FILE *fp;
char filename[FILE_SIZE];
char TEMP[FILE_SIZE];
int FILE, READ;
long int POWER;
FILE = open("/sys/class/powercap/intel-rapl/intel-rapl\\:0/energy_uj", O_RDONLY);
READ = read(FILE, TEMP, sizeof(TEMP));
POWER= strtod(TEMP,NULL);
close(FILE);
sprintf(filename,"test.csv");
fp = fopen(filename,"a+");
fprintf(fp,"\n");
fprintf(fp, "%ld", POWER);
The code compiles without any error, but in the output file I am getting value as 0. Is this due to how I am taking into account the escape sequence?
Thanks.
Since the sysfs files, while 'files' in one sense, may also be nodes, etc.. and not traditional text files, it is often best to let the shell interact with the sysfs files and simply read the needed values from a pipe following a call to popen using the shell command, e.g.
#include <stdio.h>
int main (void) {
long unsigned energy_uj = 0;
FILE *proc = popen (
"cat /sys/class/powercap/intel-rapl/intel-rapl\\:0/energy_uj", "r");
if (!proc) { /* validate pipe open for reading */
fprintf (stderr, "error: process open failed.\n");
return 1;
}
if (fscanf (proc, "%lu", &energy_uj) == 1) /* read/validate value */
printf ("energy_uj: %lu\n", energy_uj);
pclose (proc);
return 0;
}
Example Use/Output
$ ./bin/sysfs_energy_uj
energy_uj: 29378726782
That's not to say you cannot read from the sysfs files directly, but if you have any problems, then reading from a pipe is fine. For the energy_uj value, it can be read directly without issue:
#include <stdio.h>
int main (void) {
long unsigned energy_uj = 0;
FILE *fp = fopen (
"/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj", "r");
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed.\n");
return 1;
}
if (fscanf (fp, "%lu", &energy_uj) == 1) /* read/validate value */
printf ("energy_uj: %lu\n", energy_uj);
fclose (fp);
return 0;
}
Example Use/Output
$ ./bin/sysfs_energy_uj_file
energy_uj: 33636394660
I created an application that send a text file from client to server
So far i'm send it as string like this:
fp = fopen(filename, "r");
if (fp != NULL) {
newLen = fread(source, sizeof(char), 5000, fp);
if (newLen == 0) {
fputs("Error reading file", stderr);
} else {
source[++newLen] = '\0'; /* Just to be safe. */
}
}else{
printf("The file %s does not exist :(");
return 1;
}
fclose(fp);
send(s , source , strlen(source) , 0); //send file
However my professor told me I must send the file in Binary and be ready to accept a file of any size
I'm trying to figure out how to send the file in binary and break it into chunks
You can copy it one byte at a time.
Reading/writing more than a byte at a time theoretically would make it read and write more efficiently to disk. But since the binary is likely short, and disk I/O is already internally buffered it probably doesn't make a noticeable difference.
perror() is a convenient function that displays the text associated with an error code returned from the most recent UNIX system call. The text in the quotes is the title it displays before showing you the system message associated with the code.
exit(EXIT_FAILURE) exits with a -1 value which is what scripts can test to see if your program succeeded or failed, as the exit status can be retrieved for a UNIX program.
size_t is an integer type, but it's named size_t to give a hint as to what you're using it for.
If you wanted to transfer more data at a time you could. But 1-byte xfers is simple and safe and it works.
FILE *exein, *exeout;
exein = fopen("filein.exe", "rb");
if (exein == NULL) {
/* handle error */
perror("file open for reading");
exit(EXIT_FAILURE);
}
exeout = fopen("fileout.exe", "wb");
if (exeout == NULL) {
/* handle error */
perror("file open for writing");
exit(EXIT_FAILURE);
}
size_t n, m;
unsigned char buff[8192];
do {
n = fread(buff, 1, sizeof buff, exein);
if (n)
m = fwrite(buff, 1, n, exeout);
else
m = 0;
} while ((n > 0) && (n == m));
if (m)
perror("copy");
I have created a Client/Server application in C by using the SSL library. the issue i am facing is each time i send a file there are some bytes missing in the start of file.
let suppose the text file which i am sending contains
123456789
and when the client receive the file it would contains
56789
Server-Code
void sendFile(SSL* ssl)
{
char response[2048] = {0};
int read = 0;
FILE* fd;
fd = fopen("snt.txt","rb");
if (fd == NULL)
{
printf("file loading failed\n");
return;
}
while ((read=fread(response,sizeof(char),1024,fd)) > 0)
{
SSL_write(ssl,response,read);
printf("read :%d\n",read);
//puts(response);
//printf("***Data Sent***\n");
memset(response,0,1024);
}
printf("***Data Sent***\n");
fclose(fd);
}
Client Code
FILE *ft;
char filebuf[2048];
int read = 0;
int error_check=0;
ft = fopen("rcv.txt","ab");
if (ft == NULL)
{
printf("Can not open file to write\n");
return -1;
}
memset(filebuf,0,2048);
int cnk=1;
while ((error_check=BIO_read(bio,&read,sizeof(int)))>0)
{
//printf("%d read\n",read);
if (error_check==0)
break;
if (read==0)
break;
BIO_read(bio,filebuf,read);
printf("%d Chunk Recieved\n",cnk++);
//puts(filebuf);
fwrite(filebuf,sizeof(char),strlen(filebuf),ft);
memset(filebuf,0,2048);
}
printf("***File Recieved***");
fclose(ft);
the other issue is client side is not terminated, control doesn't get away from the while-loop, kindly guide me how can i tackle these issues
Assuming size(int) is 4, I'd say the 1st 4 bytes are read by this line:
while ((error_check=BIO_read(bio,&read,sizeof(int)))>0)
That leaves the rest of the data sent to this line:
BIO_read(bio,filebuf,read);
The latter reads it into filebuf which then is written to the file rcv.txt.