通过Socket发送图像(JPEG)
Sending Image (JPEG) through Socket in C Linux
我正在编写一个小的C程序,以便能够在两台计算机之间传输图像文件(从服务器到客户端都运行linux)使用TCP/IP套接字,但似乎有一个错误,因为我的图片出现在另一边损坏。
我的服务器的代码如下:
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<iostream>
#include<fstream>
#include<errno.h>
using namespace std;
int send_image(int socket){
FILE *picture;
int size, read_size;
char send_buffer[10240], verify;
picture = fopen("2.jpg", "r");
printf("Getting Picture Sizen");
if(picture == NULL) {
printf("Error Opening Image File");
}
fseek(picture, 0, SEEK_END);
size = ftell(picture);
fseek(picture, 0, SEEK_SET);
//Send Picture Size
printf("Sending Picture Sizen");
write(socket, (void *)&size, sizeof(int));
if(read_size = read(socket, &verify , sizeof(char)) < 0) {
puts("nError Receiving Verification");
}
if(verify == '1'){
printf("5n");
//Send Picture as Byte Array
printf("Sending Picture as Byte Arrayn");
while(!feof(picture)) {
//Read from the file into our send buffer
read_size = fread(send_buffer, 1, sizeof(send_buffer)-1, picture);
//Send data through our socket
write(socket, send_buffer, read_size);
//Wait for the verify signal to be received
while(read(socket, &verify , sizeof(char)) < 0);
if(verify != '1') {
printf("Error Receiving the Handshake signaln %s",&verify);
}
verify = '';
//Zero out our send buffer
bzero(send_buffer, sizeof(send_buffer));
}
}
}
int main(int argc , char *argv[])
{
int socket_desc , new_socket , c, read_size,buffer = 0;
struct sockaddr_in server , client;
char *readin;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8889 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
if((new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))){
puts("Connection accepted");
}
fflush(stdout);
if (new_socket<0)
{
perror("Accept Failed");
return 1;
}
send_image(new_socket);
close(socket_desc);
fflush(stdout);
return 0;
}
接收数据的客户端代码如下:
#include<stdio.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<sys/ioctl.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<iostream>
#include<errno.h>
using namespace std;
//This function is to be used once we have confirmed that an image is to be sent
//It should read and output an image file
int receive_image(int socket){
int buffersize = 0, recv_size = 0,size = 0, read_size, write_size;
char imagearray[10241],verify = '1';
FILE *image;
//Find the size of the image
read(socket, &size, sizeof(int));
//Send our verification signal
write(socket, &verify, sizeof(char));
//Make sure that the size is bigger than 0
if(size <= 0 ){
printf("Error has occurred. Size less than or equal to 0n");
return -1;
}
image = fopen("2.jpg", "w");
if( image == NULL) {
printf("Error has occurred. Image file could not be openedn");
return -1;
}
//Loop while we have not received the entire file yet
while(recv_size < size) {
ioctl(socket, FIONREAD, &buffersize);
//We check to see if there is data to be read from the socket
if(buffersize > 0 ) {
if(read_size = read(socket,imagearray, buffersize) < 0){
printf("%s", strerror(errno));
}
//Write the currently read data into our image file
write_size = fwrite(imagearray,1,(buffersize), image);
if(write_size != buffersize) {
printf("write and buffersizes wrong");
}
if(read_size !=write_size) {
printf("error in read write");
}
//Increment the total number of bytes read
recv_size += read_size;
//Send our handshake verification info
write(socket, &verify, sizeof(char));
}
}
fclose(image);
printf("Image successfully Received!n");
return 1;
}
int main(int argc , char *argv[])
{
int socket_desc;
struct sockaddr_in server;
char *parray;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1) {
printf("Could not create socket");
}
memset(&server,0,sizeof(server));
server.sin_addr.s_addr = inet_addr("10.42.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8889 );
//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) {
cout<<strerror(errno);
close(socket_desc);
puts("Connect Error");
return 1;
}
puts("Connectedn");
receive_image(socket_desc);
close(socket_desc);
return 0;
}
谁能帮我一下这个?我怎么也弄不清这个错误。
编辑:我已经改变了fwrites和freads回到常规的写和读,它仍然发送一个损坏的图像
你有很多问题:
- 您需要以二进制模式打开文件(
"rb"
用于读取,"wb"
用于写入),而不是默认的文本模式。在Windows(以及任何其他进行行结束转换的系统)上,stdio库在写入时将lf(字节0x0A)转换为CRLF对(两个字节0x0D 0x0A),并在读取时进行反向转换。对于非文本数据,如JPEG文件,这会破坏数据。 没有必要在每次发送之后发送你的"握手"字节。TCP/IP已经处理了确认/重发/流量控制等。您可以假设只要 -
send()
/write()
可能不会发送你要求它发送的所有数据,它们可能会部分发送。如果发生这种情况,您需要继续尝试在循环中发送剩余的缓冲区。 -
sizeof(char)
被C语言标准保证为1,很少有必要说sizeof(char)
,当你的代码没有它会更清晰 - 在客户端代码中,没有必要使用
ioctl
来确定在没有阻塞的情况下可以读取多少数据,因为您只是再次循环—当没有数据可用时,您的代码将在100% CPU下旋转。让read()
调用阻塞。如果你在笔记本电脑上运行这个代码,你的电池会感谢你的。 - 同样,客户端几乎肯定会获得部分读取,您不会在一次调用中接收整个文件。你需要写出你得到的数据,然后循环并再次接收。
- 当您在开始时通过套接字发送图像大小时,如果两个系统的端序不同,您可能会在客户端获得不同的值。为了使您的代码防弹,您需要在发送数据时将其转换为网络顺序(大端),然后在接收数据后将其转换回主机(本机)顺序。可以使用
ntohl(3)
和htonl(3)
函数对4字节值进行这些转换。
send()
/write()
返回一个正值,那么另一个对等体收到了许多字节。现在可以正常工作了。
,
马里奥。
客户:#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<iostream>
#include<fstream>
#include<errno.h>
using namespace std;
//This function is to be used once we have confirmed that an image is to be sent
//It should read and output an image file
int receive_image(int socket)
{ // Start function
int buffersize = 0, recv_size = 0,size = 0, read_size, write_size, packet_index =1,stat;
char imagearray[10241],verify = '1';
FILE *image;
//Find the size of the image
do{
stat = read(socket, &size, sizeof(int));
}while(stat<0);
printf("Packet received.n");
printf("Packet size: %in",stat);
printf("Image size: %in",size);
printf(" n");
char buffer[] = "Got it";
//Send our verification signal
do{
stat = write(socket, &buffer, sizeof(int));
}while(stat<0);
printf("Reply sentn");
printf(" n");
image = fopen("capture2.jpeg", "w");
if( image == NULL) {
printf("Error has occurred. Image file could not be openedn");
return -1; }
//Loop while we have not received the entire file yet
int need_exit = 0;
struct timeval timeout = {10,0};
fd_set fds;
int buffer_fd, buffer_out;
while(recv_size < size) {
//while(packet_index < 2){
FD_ZERO(&fds);
FD_SET(socket,&fds);
buffer_fd = select(FD_SETSIZE,&fds,NULL,NULL,&timeout);
if (buffer_fd < 0)
printf("error: bad file descriptor set.n");
if (buffer_fd == 0)
printf("error: buffer read timeout expired.n");
if (buffer_fd > 0)
{
do{
read_size = read(socket,imagearray, 10241);
}while(read_size <0);
printf("Packet number received: %in",packet_index);
printf("Packet size: %in",read_size);
//Write the currently read data into our image file
write_size = fwrite(imagearray,1,read_size, image);
printf("Written image size: %in",write_size);
if(read_size !=write_size) {
printf("error in read writen"); }
//Increment the total number of bytes read
recv_size += read_size;
packet_index++;
printf("Total received image size: %in",recv_size);
printf(" n");
printf(" n");
}
}
fclose(image);
printf("Image successfully Received!n");
return 1;
}
int main(int argc , char *argv[])
{
int socket_desc;
struct sockaddr_in server;
char *parray;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1) {
printf("Could not create socket");
}
memset(&server,0,sizeof(server));
server.sin_addr.s_addr = inet_addr("10.0.0.30");
server.sin_family = AF_INET;
server.sin_port = htons( 8889 );
//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) {
cout<<strerror(errno);
close(socket_desc);
puts("Connect Error");
return 1;
}
puts("Connectedn");
receive_image(socket_desc);
close(socket_desc);
return 0;
}
服务器: #include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<iostream>
#include<fstream>
#include<errno.h>
using namespace std;
int send_image(int socket){
FILE *picture;
int size, read_size, stat, packet_index;
char send_buffer[10240], read_buffer[256];
packet_index = 1;
picture = fopen("capture.jpeg", "r");
printf("Getting Picture Sizen");
if(picture == NULL) {
printf("Error Opening Image File"); }
fseek(picture, 0, SEEK_END);
size = ftell(picture);
fseek(picture, 0, SEEK_SET);
printf("Total Picture size: %in",size);
//Send Picture Size
printf("Sending Picture Sizen");
write(socket, (void *)&size, sizeof(int));
//Send Picture as Byte Array
printf("Sending Picture as Byte Arrayn");
do { //Read while we get errors that are due to signals.
stat=read(socket, &read_buffer , 255);
printf("Bytes read: %in",stat);
} while (stat < 0);
printf("Received data in socketn");
printf("Socket data: %cn", read_buffer);
while(!feof(picture)) {
//while(packet_index = 1){
//Read from the file into our send buffer
read_size = fread(send_buffer, 1, sizeof(send_buffer)-1, picture);
//Send data through our socket
do{
stat = write(socket, send_buffer, read_size);
}while (stat < 0);
printf("Packet Number: %in",packet_index);
printf("Packet Size Sent: %in",read_size);
printf(" n");
printf(" n");
packet_index++;
//Zero out our send buffer
bzero(send_buffer, sizeof(send_buffer));
}
}
int main(int argc , char *argv[])
{
int socket_desc , new_socket , c, read_size,buffer = 0;
struct sockaddr_in server , client;
char *readin;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8889 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
if((new_socket = accept(socket_desc, (struct sockaddr *)&client,(socklen_t*)&c))){
puts("Connection accepted");
}
fflush(stdout);
if (new_socket<0)
{
perror("Accept Failed");
return 1;
}
send_image(new_socket);
close(socket_desc);
fflush(stdout);
return 0;
}
我修改了@mmirand6 answer,使服务器在客户端发送图像时接收图像(即,上面的示例反之亦然)。同样,这个例子使用了localhost。另一个区别是,服务器永远不会退出,并一直等待新的连接。
server.cpp
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<iostream>
#include<fstream>
#include<errno.h>
using namespace std;
int receive_image(int socket)
{ // Start function
int buffersize = 0, recv_size = 0,size = 0, read_size, write_size, packet_index =1,stat;
char imagearray[10241],verify = '1';
FILE *image;
//Find the size of the image
do{
stat = read(socket, &size, sizeof(int));
}while(stat<0);
/*printf("Packet received.n");
printf("Packet size: %in",stat);
printf("Image size: %in",size);
printf(" n");*/
char buffer[] = "Got it";
//Send our verification signal
do{
stat = write(socket, &buffer, sizeof(int));
}while(stat<0);
printf("Reply sentn");
printf(" n");
image = fopen("res.ppm", "w");
if( image == NULL) {
printf("Error has occurred. Image file could not be openedn");
return -1; }
//Loop while we have not received the entire file yet
int need_exit = 0;
struct timeval timeout = {10,0};
fd_set fds;
int buffer_fd, buffer_out;
while(recv_size < size) {
//while(packet_index < 2){
FD_ZERO(&fds);
FD_SET(socket,&fds);
buffer_fd = select(FD_SETSIZE,&fds,NULL,NULL,&timeout);
if (buffer_fd < 0)
printf("error: bad file descriptor set.n");
if (buffer_fd == 0)
printf("error: buffer read timeout expired.n");
if (buffer_fd > 0)
{
do{
read_size = read(socket,imagearray, 10241);
}while(read_size <0);
/*printf("Packet number received: %in",packet_index);
printf("Packet size: %in",read_size);*/
//Write the currently read data into our image file
write_size = fwrite(imagearray,1,read_size, image);
//printf("Written image size: %in",write_size);
if(read_size !=write_size) {
printf("error in read writen"); }
//Increment the total number of bytes read
recv_size += read_size;
packet_index++;
/*printf("Total received image size: %in",recv_size);
printf(" n");
printf(" n");*/
}
}
fclose(image);
printf("Image successfully Received!n");
return 1;
}
int main(int argc , char *argv[])
{
int socket_desc , new_socket , c, read_size,buffer = 0;
struct sockaddr_in server , client;
char *readin;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8889 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3); // int listen(int s, int backlog); | `backlog` (3)
//limits the number of outstanding connections in the socket's listen
//queue to the value specified by the backlog argument.
while(true)
{
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
// waits for a connection. returns -1 on failure, a positive val on success
if((new_socket = accept(socket_desc, (struct sockaddr *)&client,(socklen_t*)&c)))
{
puts("Connection accepted");
cout << "new_socket = " << new_socket << "n";
}
fflush(stdout);
if (new_socket<0)
{
perror("Accept Failed, trying again");
continue;
}
// receive image
receive_image(new_socket);
}
close(socket_desc);
fflush(stdout);
return 0;
}
client.cpp
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<iostream>
#include<fstream>
#include<errno.h>
using namespace std;
//This function is to be used once we have confirmed that an image is to be sent
//It should read and output an image file
int send_image(int socket)
{
FILE *picture;
int size, read_size, stat, packet_index;
char send_buffer[10240], read_buffer[256];
packet_index = 1;
picture = fopen("test.ppm", "r");
printf("Getting Picture Sizen");
if(picture == NULL) {
printf("Error Opening Image File"); }
fseek(picture, 0, SEEK_END);
size = ftell(picture);
fseek(picture, 0, SEEK_SET);
printf("Total Picture size: %in",size);
//Send Picture Size
printf("Sending Picture Sizen");
write(socket, (void *)&size, sizeof(int));
//Send Picture as Byte Array
printf("Sending Picture as Byte Arrayn");
do { //Read while we get errors that are due to signals.
stat=read(socket, &read_buffer , 255);
printf("Bytes read: %in",stat);
} while (stat < 0);
printf("Received data in socketn");
printf("Socket data: %cn", read_buffer);
while(!feof(picture)) {
//while(packet_index = 1){
//Read from the file into our send buffer
read_size = fread(send_buffer, 1, sizeof(send_buffer)-1, picture);
//Send data through our socket
do{
stat = write(socket, send_buffer, read_size);
}while (stat < 0);
printf("Packet Number: %in",packet_index);
printf("Packet Size Sent: %in",read_size);
printf(" n");
printf(" n");
packet_index++;
//Zero out our send buffer
bzero(send_buffer, sizeof(send_buffer));
}
}
int main(int argc , char *argv[])
{
int socket_desc;
struct sockaddr_in server;
char *parray;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1) {
printf("Could not create socket");
}
memset(&server,0,sizeof(server));
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8889 );
//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) {
cout<<strerror(errno);
close(socket_desc);
puts("Connect Error");
return 1;
}
puts("Connectedn");
send_image(socket_desc);
//close(socket_desc);
return 0;
}
用$gcc client.cpp -lstdc++ -o client
编译
相关文章:
- 如何从未签名的char*数组中获取JPEG图像数组
- 意外的摄像头校准结果与JPEG图像和EXIF方向上的OPENCV结果
- 如何使用avcodec从OpenCV::Mat类型的jpeg图像创建视频
- 带有 JPEG 图像的组合框
- 如何在Qt中将Jpeg Base64字符串转换为jpeg图像
- 如何将 JPEG 注释添加到现有的 JPEG 图像文件
- 如何通过串行端口接收 JPEG 图像
- 当使用GDI+创建时,两个具有相同维度的JPEG图像是否具有相同的标头
- 用c++将数组编码为jpeg图像
- 用于获取JPEG图像大小的C++库
- 如何在Qt的主窗口上完全显示jpeg图像
- 从JPEG图像中提取RGB,使用libjpeg c++库
- 使用c++在Qt中添加jpeg图像文件
- 如何从磁盘加载Jpeg图像并创建视频文件?Avi等),而无需在c++中使用opencv
- 使用boost::gil从内存中读取JPEG图像
- Linux CGI Web API -如何在c++下输出二进制JPEG图像
- 解码JPEG图像的快速方法
- 用于将JPEG图像转换为TIFF格式的C, c++或Objective-C代码
- 通过http GET请求接收JPEG图像
- opencv从缓冲区读取jpeg图像