关于socket的问题,兼散分(四个裤衩了,还没有散分:))

scmsir 2004-12-21 06:24:45
我的程序需要进行如下操作:
1、从客户端传送一个音频文件到服务器。
2、服务器根据音频文件进行处理,处理结束后将处理结果传回客户端。

不知道这两个操作可否用同一个socket.因为我第一个操作传送的二进制而第二个操作传送的是文本。而且我需要知道第一个操作什么时候结束。本来我在第一个步骤结束之后发送一个特定的字符串来表示结束,但是如果最后接受的字符串的长度比我的标志字符串长度短的话就没有办法判断了。

需要大家提供好的建议,或者把我上边的推倒重来也可以。但是希望流程不要太复杂,我不需要维护连接联表。
...全文
305 点赞 收藏 37
写回复
37 条回复
scmsir 2004年12月24日
呵呵,问题已经解决了。
大家多顶,过几天就结铁。
回复 点赞
beyondtkl 2004年12月24日
可以。。。定義不同的命令字 即可

比如 發送音頻文件 包頭 就: CMD_SEND_SOUND
發送接收ok標志 就: CMD_RCV_SOUND_OK

.........
當然 你還可以添加其它的信息。。
回复 点赞
msm 2004年12月24日
散就领!
回复 点赞
ljhnew 2004年12月24日
对于int、float等数据类型的高低字节次序,一般与机器的硬件有关,编译器只是根据操作系统针对硬件的不同而定义的,在同一种硬件平台上,编译器的处理是一样的,不管是Windows还是Unix/Linux。我们常用的PC机即386平台(包括intel、AMD等)都是高字节在前,而sparc则是高字节在后(Big Ending),为了数据传输的统一,TCP/IP协议规定了网络字节次序即高字节在后,所以我们在网络编程时经常用到htons(host to network short短整数)、htonl、ntohs、ntohl等等,在普通的PC机上,我们必须用这些编译器提高的宏或函数来转换多字节数据(short int、long、float、double等)。

如果要考虑到可移植性,你需要将数据的传送进行处理,如int:
发送:
int my_len=100;
int my_intbuftosend;
my_intbuftosend=htonl(my_len);
send(sock,&my_intbuftosend,sizeof(my_intbuftosend));
接收:
int my_len=0;
int my_intbuftorecv;
recv(sock,&my_intbuftorecv,&my_len);
int my_int=ntohl(my_intbuftorecv);
更多类型的外部数据传送,可以参考sun公司的XDR数据传输协议,已经作为RFC的标准来使用了。
回复 点赞
scmsir 2004年12月24日
大家帮忙看一下,这么一点的代码怎么就会有问题呢?

我这个函数在一个只有一个主线程的程序中调用就是正常的,但是在一个多线程的程序中调用就会不正常。

首先,send 的数据好像少了最后一个包,而且因为服务器接受的是0,我怀疑这边的socket关闭了,但是在另外一种情况下是正常的,这说明代码是没有问题的。但是不知道为什么会有错误?而且我的recv接受的值是-1。
回复 点赞
scmsir 2004年12月24日
void sendWave()
{
#define PORT 34001
#define SERVER_IP "192.168.0.52"

int s;
int fd;
int status;
int j=1;

char songsID[6]="";//songs id
int songsNum=0;//the songsnum of 8,0-8;
int songsIDNum=0;//songsidnum 0-4;
int bufferNumBegin=0;
char temp[100];
int sended=0;

struct sockaddr_in addr;
struct stat buf;
int size;
char buffer[1024];

printf("into send wave\n");
if((s = socket(AF_INET,SOCK_STREAM,0))<0)
{
printf("create socket failed");
exit(1);
}
fd=open("testwav",O_RDONLY);
if (fd<0)
{
printf("open testwav erro");
exit(1);
}
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port=htons(PORT);
addr.sin_addr.s_addr = inet_addr(SERVER_IP);
if(connect(s,&addr,sizeof(addr))<0)
{
printf("connect failed");
exit(1);
}
printf("connect ok\n");
stat("testwav",&buf);
size=buf.st_size;
if(send(s,&size,sizeof(size),0)<0)
printf("send length failed");
while(1)
{
bzero(buffer,sizeof(buffer));
status=read(fd,buffer,sizeof(buffer));
sended+=status;
if (status==0)
{
close(fd);
break;
}
if(send(s,buffer,status,0)<0)
{
printf("send failed");
}
else
{
sprintf(temp,"the size of send is %d,the socket = %d\n",sended,s);
printf(temp);
}
}
status=recv(s,buffer,sizeof(buffer),0);
sprintf(temp,"the socket is=%d\n",s);
printf(temp);
sprintf(temp,"the recv return %d\n",status);//在多线程的程序里面接受0,在其他情况下正常
printf(temp);
sprintf(temp,"the songs id is %s\n",buffer);
printf(temp);

if(buffer[0])
{
for(songsNum=0;songsNum<8;songsNum++)
{
printf("add songs");
bufferNumBegin=songsNum*6;
for(songsIDNum=0;songsIDNum<5;songsIDNum++)
{
songsID[songsIDNum]=buffer[bufferNumBegin++];
}
songsID[5]='\0';
printf(songsID);
}
}
close(fd);
close(s);
}
回复 点赞
chan2chen 2004年12月24日
接分
回复 点赞
younggle 2004年12月24日
对于int、float等数据类型的高低字节次序,一般与机器的硬件有关,编译器只是根据操作系统针对硬件的不同而定义的,在同一种硬件平台上,编译器的处理是一样的,不管是Windows还是Unix/Linux。我们常用的PC机即386平台(包括intel、AMD等)都是高字节在前,而sparc则是高字节在后(Big Ending),为了数据传输的统一,TCP/IP协议规定了网络字节次序即高字节在后,所以我们在网络编程时经常用到htons(host to network short短整数)、htonl、ntohs、ntohl等等,在普通的PC机上,我们必须用这些编译器提高的宏或函数来转换多字节数据(short int、long、float、double等)。

如果要考虑到可移植性,你需要将数据的传送进行处理,如int:
发送:
int my_len=100;
int my_intbuftosend;
my_intbuftosend=htonl(my_len);
send(sock,&my_intbuftosend,sizeof(my_intbuftosend));
接收:
int my_len=0;
int my_intbuftorecv;
recv(sock,&my_intbuftorecv,&my_len);
int my_int=ntohl(my_intbuftorecv);
更多类型的外部数据传送,可以参考sun公司的XDR数据传输协议,已经作为RFC的标准来使用了。
回复 点赞
comman_wang 2004年12月23日
我第一部先发送的文件长度,再windows下面没有问题。但是,因为我的客户端是linux,所以发的长度我读出来的值不对,有经验的指点一下?
我用的是int
int dwLength=0;
sockRecv.Receive(&dwLength,4);

-------------------------------------------------------------------------------

会不会windows和linux下编译器对于int的定义长度不同?调试时可以把发送端和接收端二进制码分别打印出来,对比一下确认是数据传输错误还是分包长度的问题。
回复 点赞
hony688 2004年12月22日
用TCP可以实现稳定的数据传输,不要用UDP,否则会出现数据包丢失的情况,若你想用一个特殊的字符来确定发送是否结束的话,用TCP。
回复 点赞
chqu18 2004年12月22日
接了分加角了在说
回复 点赞
ljhnew 2004年12月22日
接收到的数据长度不一定就是发的长度。

这是由TCP/IP协议决定的,特别是“报文的分组发送”,当IP层在传输中,不能把所有的数据一次传送出去,就会将数据包分组,所以就会导致出你的问题。这只是一个比较简单的解释,如果你希望了解根详细的环节,可以参考一下具体的TCP/IP协议。如在我们普通的以太网上,如果你一次发送1M的数据,而以太网上规定一次的传输最大数据为1500左右(MTU),此时,你很可能在一次recv调用时并不会得到所有的1M数据,你可以用flags=MSG_WAITALL来实现,不过一次接收1M的数据,对于一般的TCP/IP协议栈来说,比较难以处理,所以,你可以采用循环多次调用(最好是block阻塞模式)来得到数据。
对于发送数据包来说,也是同样道理,如果你一次发送的数据超过了协议栈的缓冲(特别是在单片机嵌入式系统中),那么发送调用就会给你返回一个实际发送出的数据或直接返回失败。
回复 点赞
liudancodeman 2004年12月22日
接分
回复 点赞
zhangqu_980371 2004年12月22日
上面都差不多说完了,我也就不献丑了,就等你的分升星了对啊
回复 点赞
xenke 2004年12月22日
上面都差不多说完了,我也就不献丑了,就等你的分升星了
回复 点赞
scmsir 2004年12月22日
我第一部先发送的文件长度,再windows下面没有问题。但是,因为我的客户端是linux,所以发的长度我读出来的值不对,有经验的指点一下?
我用的是int
int dwLength=0;
sockRecv.Receive(&dwLength,4);
回复 点赞
ljhnew 2004年12月22日
如果你希望传送文件,我倒是建议你用现成的FTP系统调用就可以实现了,而你可以不必关心过多的如TCP等的传输细节了。
回复 点赞
Wenxy1 2004年12月22日
混分。:)
回复 点赞
ljhnew 2004年12月21日
最好用TCP协议,调用recv接收数据时,将flags指定为MSG_WAITALL表示必须接收到指定的所有1024个数据时才返回。
回复 点赞
comman_wang 2004年12月21日
需要循环接收,1024个字节可能不是一次接收完,需判断接收到的数据长度。
回复 点赞
发动态
发帖子
网络编程
创建于2007-09-28

7880

社区成员

6.4w+

社区内容

VC/MFC 网络编程
社区公告
暂无公告