请问大家一个linux网络传输的问题?
本帖最后由 dingzhou2008 于 2013-09-08 12:52 编辑下面是两个linux下网络传输程序,server.c和client.c,分别发送和接收照片数据。照片大小32K。编译后在ubuntu下运行正常图片正确,但交叉编译后server在开发板上运行,client在ubuntu下运行,接收到的图片数据能显示,但有错位。请大家帮忙分析一下。
server.c如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <string.h>
#include "proto.h"
#define BUFSIZE 128 //1024
#define STRSIZE 40
static void server_job(int sd) {
char buf;
int len, i, count;
char jpgbuf;
char statebuf;
FILE *input_file;
if ((input_file = fopen("1.jpg", "rb")) == NULL) {
fprintf(stderr, "can't open 1.jpg\n");
return;
}
fread(jpgbuf, 32768, 1, input_file);
for (count = 0; count < 32; count++) {
if (send(sd, jpgbuf+count*1024, 1024, 0) < 0) {
printf("Send File:\t JPEG picture Failed\n");
}
}
}
int main() {
char ipstr;
int sd, newsd;
struct sockaddr_in laddr, raddr;
socklen_t raddr_len;
pid_t pid;
sd = socket(AF_INET, SOCK_STREAM, 0/*IPPROTO_TCP,IPPROTO_SCTP*/);
if (sd < 0) {
perror("socket()");
exit(1);
}
int val = 1;
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
perror("setsockopt(SO_REUSEADDR)");
}
laddr.sin_family = AF_INET;
laddr.sin_port = htons(atoi(SERVERPORT));
inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr);
if (bind(sd, (void *) &laddr, sizeof(laddr)) < 0) {
perror("bind()");
exit(1);
}
if (listen(sd, 200) < 0) {
perror("listen()");
exit(1);
}
raddr_len = sizeof(raddr); /*!!!!!!!!*/
while (1) {
newsd = accept(sd, (void *) &raddr, &raddr_len);
if (newsd < 0) {
perror("accept()");
exit(1);
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork()");
exit(1);
}
if (pid == 0) {
close(sd);
inet_ntop(AF_INET, &raddr.sin_addr, ipstr, STRSIZE);
printf("Client:%s:%d\n", ipstr, ntohs(raddr.sin_port));
server_job(newsd);
close(newsd);
exit(1);
}
close(newsd);
wait(NULL);
}
exit(0);
}
client.c如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "proto.h"
/* Address to accept any incoming messages.*/
#define INADDR_ANY ((in_addr_t) 0x00000000)
#define BUFFER_SIZE 1024
/* Set N bytes of S to 0.*/
extern void bzero(void *__s, size_t __n)
__THROW __nonnull ((1));
char recieveBuffer;
int leftRecieveChars;
int currentIndex = 0;
int sd;
char getOneChar() {
currentIndex++;
if (leftRecieveChars == 0) {
bzero(recieveBuffer, BUFFER_SIZE);
do {
leftRecieveChars = recv(sd, recieveBuffer, BUFFER_SIZE, 0);
if (leftRecieveChars < 0) {
printf("Server Recieve Data Failed!\n");
exit(1);
}
} while (leftRecieveChars == 0);
currentIndex = 0;
}
leftRecieveChars--;
return recieveBuffer;
}
int main(int argc, char *argv[]) {
FILE *fp;
int i, jpegSize;
long long stamp;
struct sockaddr_in raddr;
char numberBuf;
if (argc < 2) {
fprintf(stderr, "Usage...\n");
exit(1);
}
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0) {
perror("socket()");
exit(1);
}
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET; //internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY); //INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口
//把客户机的socket和客户机的socket地址结构联系起来
if (bind(sd, (struct sockaddr*) &client_addr, sizeof(client_addr))) {
printf("Client Bind Port Failed!\n");
exit(1);
}
raddr.sin_family = AF_INET;
raddr.sin_port = htons(atoi(SERVERPORT));
inet_pton(AF_INET, argv, &raddr.sin_addr);
if (connect(sd, (void *) &raddr, sizeof(raddr)) < 0) {
perror("connect()");
exit(1);
}
int count = 0, cnt = 0;
char name;
//while (1) {
printf("Begin recieve data.the num is %d!\n", cnt);
cnt++;
jpegSize = 32768;
char fileBuf;
bzero(fileBuf, jpegSize);
//printf("Begin receive JPG date !\n");
for (count = 0; count < 32; count++) {
leftRecieveChars = recv(sd, fileBuf + count * 1024, 1024, 0);
}
sprintf(name, "%d.jpg", count);
count++;
if (count >= 7)
count = 0;
fp = fopen(name, "w");
int writeLength = fwrite(fileBuf, sizeof(char), 32768, fp);
//printf("writeLength to file : %d\n", writeLength);
if (writeLength < 32768) {
printf("File:\t%s Write Failed\n", "1.jpeg");
fclose(fp);
exit(1);
}
fclose(fp);
return 0;
}
顶一个!大家帮忙啊! 本帖最后由 huangya90 于 2013-09-04 14:05 编辑
程序能运行,一般情况下是不会出问题的。但还是一个错误的程序。
tcp是面向字节流的,对于什么是面向字节流,请参考任何一本网络教材(其实很多人对tcp是面向字节流根本没有理解)。for (count = 0; count < 32; count++) {
leftRecieveChars = recv(sd, fileBuf + count * 1024, 1024, 0);
}这段代码中的每调用一次recv,不一定会收到1024个字节,所以调用32次可能收到小于1024*32个字节。这里就发生了这种情况。用命令
od -Ad -t u1 正确的图片.jpg >正确的图片.jpg.udecimal;od -Ad -t u1 错误的图片.jpg >错误的图片.jpg.udecimal;可以得到两张图片的无符号整数类型。用命令cmp 正确的图片.jpg 错误的图片.jpg可以发现在第3921个字节出现了第一个不相同的字节。用vim打开文件:错误的图片.jpg.udecimal,正确的图片.jpg.udecimal。找到第3921个字节,如下图所示:
http://p13.freep.cn/p.aspx?u=v20_p13_photo_1309041339248573_0.jpg(左边的是文件错误的图片.jpg.udecimal,右边的是文件正确的图片.jpg.udecimal。图中的0003920表示第3921个字节)。错误的图片.jpg.udecimal从3921-4096个字节显示的数值是0(fileBuf是全局变量 ,每个字节默认值是0),而正确的图片.jpg.udecimal数值不是0。错误的图片.jpg.udecimal从地址0004960对应了正确的图片.jpg.udecima从地址0003920开始的数值,说明你在第四次调用recv的时候并没有收到 1024个字节。所以你接收了错误的数据。下面的recv调用也发生了这种情况。知道了原因, 我想你应该知道怎么改程序了。
另外说两点:
1.client.c中getOneChar() 有什么用?你都没有调用。
2.请以后粘贴代码的时候使用插入的方式,不要直接粘贴,代码中出现笑脸了。
多谢指点,说的太对了,严谨的作风让我自愧不如,我以后会改过,多谢大牛。
页:
[1]