我撰寫了以下函式,它通過套接字從服務器讀取 http 回應。我在閱讀像
即使讀取回傳正確的位元組數,讀取也不會向緩沖區添加資料。
功能:
unsigned char *read_unknown_size(int fd) {
int available_buf_size = 1000, tot_read = 0, curr_read_size;
unsigned char *buf = calloc(available_buf_size, 1), *tmp_ptr;
if (buf) {
while ((curr_read_size = (int) read(fd, buf tot_read, available_buf_size - tot_read)) != 0) {
if (curr_read_size == -1) {
perror("failed to read\n");
//todo free mem
exit(EXIT_FAILURE);
} else {
tot_read = curr_read_size;
if (tot_read >= available_buf_size) { //the buffer is full
available_buf_size *= 2;
tmp_ptr = realloc(buf, available_buf_size tot_read);
if (tmp_ptr) {
buf = tmp_ptr;
memset(buf tot_read, 0, available_buf_size - tot_read);
}
else {
fprintf(stderr,"realloc failed\n");
exit(EXIT_FAILURE);
}
}
}
}
} else {
fprintf(stderr,"calloc failed\n");
exit(EXIT_FAILURE);
}
return buf;
}
一次讀取大小為 1000 后的緩沖區:
0x563a819da130 "HTTP/1.1 200 OK\r\n日期:2021 年 11 月 23 日星期二 19:32:01 GMT\r\n服務器:Apache\r\n升級:h2,h2c\r\n連接:升級,關閉\r\nLast-修改時間:2014 年 1 月 11 日星期六 01:32:55 GMT\r\n接受范圍:位元組\r\n內容長度:3900\r\n快取控制:max-age=2592000\r\n到期:12 月 23 日星期四2021 19:32:01 GMT\r\n內容型別:影像/jpeg\r\n\r\nGIF89",<不完整序列\375>
共379個字。
編輯: 讀取資料后,我將其寫入新檔案,文本頁面作業正常,但無法打開影像。
uj5u.com熱心網友回復:
我相信這read_unknown_size是有效的,但呼叫者只是通過使用printf("%s", buf)或類似的方式列印出緩沖區,直到第一個 NUL 字符。[1]這是錯誤的,原因有二:
- 如果讀取的資料包含 NUL,它將過早停止輸出。
- 如果讀取的資料不包含 NUL,它將讀取到緩沖區末尾之外。
呼叫者需要準確輸出緩沖區中的字符數。但是,呼叫者無法確定緩沖區中有多少字符。因此,為了對函式的結果做任何有用的事情,函式不僅需要回傳緩沖區,還需要回傳它讀取的字符數。
// Reads until EOF is encountered.
// Returns 0 on success.
// Returns -1 and sets errno on error.
int read_rest(int fd, unsigned char **buf_ptr, size_t *total_read_ptr) {
unsigned char *buf = NULL;
size_t buf_size = 0;
size_t total_read = 0;
while (1) {
if ( total_read == buf_size ) {
buf_size *= 2; // Refine this.
unsigned char *tmp = realloc(buf, buf_size);
if (!tmp)
goto ERROR;
buf = tmp;
}
ssize_t chunk_size = read(fd, buf total_read, buf_size - total_read);
if ( chunk_size < 0 )
goto ERROR;
if ( chunk_size == 0 ) {
unsigned char *tmp = realloc(buf, total_read);
if (tmp)
buf = tmp;
*buf_ptr = buf;
*total_read_ptr = total_read;
return 0;
}
total_read = chunk_size;
}
ERROR:
free(buf);
*buf_ptr = NULL;
*total_read_ptr = 0;
return -1;
}
示例呼叫者:
unsigned char *buf;
size_t size;
if ( read_rest(in_fd, &buf, &size) == -1 ) {
perror("Can't read from socket");
exit(EXIT_FAILURE);
}
現在您有足夠的資訊來列印緩沖區的內容(例如使用write)。
// Returns 0 on success.
// Returns -1 and sets errno on error.
int write_full(int fd, const unsigned char *buf, size_t count) {
while ( count > 0 ) {
ssize_t chunk_size = write(fd, buf, count);
if ( chunk_size < 0 )
return -1;
buf = chunk_size;
count -= chunk_size;
}
}
示例呼叫者:
if ( write_full(out_fd, buf, size) == -1 ) {
perror("Can't write to file");
exit(EXIT_FAILURE);
}
對原代碼的評論:
- 在使用演員表之前要仔細考慮。使用
(int)read(...)沒有意義。這是不正確的。 - 最好
perror在發生錯誤時包含實際錯誤(就像那樣)。 - 最好在 I/O 功能之外列印錯誤訊息。
- 請記住,NUL 在 GIF 檔案中很常見,您可以在第 7 個字符(緊接在 之后
GIF89a)就有一個。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/364681.html
下一篇:為什么我不能在C中列印指標的值?
