麻烦!麻烦!(传输两个结构体)高手们快来帮小弟一把
现需要传输两个结构体,比如HEAD和DATA。我把HEAD强制转换成char *sendstr1,然后把DATA转换成char *sendstr2。如果把这两个结构体分两步send出去,服务器方接收以后强制转换成结构体形式,可以得到正确结果。但分两次send存在延时问题,现在想一次send把两个结构体发出去,怎么实现?我的做法是把sendstr1和sendstr2整和在一起发送,但那样发送好象有些问题,服务器方接收不到正确信息。代码我给拉过来,大伙帮忙分析一下。
问题点数:50、回复次数:10Top
1 楼ff324()回复于 2002-12-14 15:48:30 得分 0
client端代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>
#define SERVER "127.0.0.1"
#define PORT 5250
struct HEAD
{
char h1[4];
char h2[6];
};
struct DATA
{
char d1[4];
char d2[6];
};
int main( )
{
int sockfd,n;
struct sockaddr_in ser_addr;
char *sendstr1;
char *sendstr2;
struct HEAD *head;
struct DATA *data;
head=(struct HEAD*)malloc(sizeof(struct HEAD));
data=(struct DATA*)malloc(sizeof(struct DATA));
WSADATA wsadata;
WSAStartup(MAKEWORD(2,2), &wsadata);
strcpy(head->h1,"6");
strcpy(head->h2,"8");
sendstr1=(char *)head;
strcpy(data->d1,"16");
strcpy(data->d2,"18");
sendstr2=(char *)data;
strncat(sendstr1,sendstr2,sizeof(struct HEAD));
int length=(sizeof(struct HEAD)+sizeof(struct DATA));
memset(&ser_addr,0,sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = inet_addr(SERVER);
ser_addr.sin_port = htons(PORT);
sockfd=socket(AF_INET,SOCK_STREAM,0);
if (sockfd<0) {
printf("0x%x:%d error\n",ntohl(ser_addr.sin_addr.s_addr),ntohs(ser_addr.sin_port));
exit(1);
}
if(connect(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr))<0){
printf("connect error\n");
exit(1);
}
printf("connected\n");
if(send(sockfd, sendstr1,length,0)<0){
printf("Send error!\n");
exit(0);
}
printf("Send ok!\n");
WSACleanup();
}
server端代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>
#define PORT 5250
struct HEAD
{
char h1[4];
char h2[6];
};
struct DATA
{
char d1[4];
char d2[6];
};
int main( )
{
int sockfd,new_fd,n,sin_size;
struct sockaddr_in ser_addr;
struct sockaddr_in clt_addr;
char recvs[100];
struct HEAD *head;
struct DATA *data;
char s1[10];
char s2[10];
char n1[10];
char n2[10];
WSADATA wsadata;
WSAStartup(MAKEWORD(2,2), &wsadata);
head=(struct HEAD*)malloc(sizeof(struct HEAD));
data=(struct DATA*)malloc(sizeof(struct DATA));
memset(&ser_addr,0,sizeof(ser_addr));
sockfd=socket(AF_INET,SOCK_STREAM,0);
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr=htonl(INADDR_ANY);
ser_addr.sin_port = htons(PORT);
if(ser_addr.sin_port==0){
printf("Bad server port! %d!\n",ntohs(ser_addr.sin_port));
return -2;
}
if (sockfd<0) {
printf("0x%x:%d error\n",ntohl(ser_addr.sin_addr.s_addr),ntohs(ser_addr.sin_port));
exit(1);
}
if (bind(sockfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr))) {
printf("Cannot bind server port!");
return -4;
}
listen(sockfd,100);
while (1)
{
sin_size=sizeof(struct sockaddr_in);
printf("Listening at: 0x%x:%d!\n",ntohl(ser_addr.sin_addr.s_addr),ntohs(ser_addr.sin_port));
new_fd=accept(sockfd,(struct sockaddr*)&clt_addr,&sin_size);
if((n=recv(new_fd,recvs,sizeof(struct HEAD),0))==0) {
printf("read error!\n");
}
recvs[n]=0;
head=(struct HEAD*)recvs;
strcpy(s1,head->h1);
strcpy(s2,head->h2);
if((n=recv(new_fd,recvs,sizeof(struct DATA),0))==SOCKET_ERROR) {
printf("read error:%d\n",WSAGetLastError());
}
recvs[n]=0;
data=(struct DATA*)recvs;
strcpy(n1,data->d1);
strcpy(n2,data->d2);
printf("read ok!\n %s\n",n1);
printf("read ok!\n %s\n",n2);
}
WSACleanup();
}
Top
2 楼ff324()回复于 2002-12-14 15:52:06 得分 0
怎么这么长,忘了写注释了,大伙主要看一下send和recv及里面的参数吧Top
3 楼HongHuer(Hello,world.)回复于 2002-12-14 16:33:48 得分 10
struct HEAD
{
char h1[4];
char h2[6];
};
struct DATA
{
char d1[4];
char d2[6];
};
struct NEWS
{
struct HEAD head;
struct DATA data;
};
send and receive the struct NEWS
Top
4 楼cooljjyy(叽叽歪歪)回复于 2002-12-14 16:42:24 得分 10
不能想得太单纯,虽然你是分两次发送,但是服务器说不定只收了一次,比如你两次分别发送2和2字节,服务器可能收到1和3字节两次,也可能是一次收到4字节,用楼上的方法可以,但是最终为了你的程序安全考虑,recv数据的时候一定要循环进行,直到判断收到所有的字节为止,因为甚至可能你能recv到4个1字节的数据Top
5 楼omale(代码机器.net)回复于 2002-12-14 21:45:11 得分 5
同意Top
6 楼anyiflyer(代码在我心中!)回复于 2002-12-15 14:20:39 得分 25
如果是LAN,不可能出现先发送的数据后收到的情况,但是WAN就可能出现了.但是如果是TCP协议,TCP自己会重组的.一般地说,发送1K的数据是安全的,因为TCP的windows是8K,另外,跟你发送的数据是什么类型没有一点关系,在TCP协议中只认识字节,或者说TCP只有字节的概念,它也不关心数据是什么类型.
struct type1{
int i ;
long k ;
}*ptype1;
struct type2{
char str[128];
float f;
}*ptype2;
char buffer[1024];
ptype1 = ( struct type1 *)buffer ;
ptype1->i = 100 ;
ptype1->k = 5000 ;
ptype2 = ( struct type2 *)(buffer + sizeof( struct type1));
sprintf( ptype2->str, "I love u");
ptype2->f = 122.2;
ptcpsocket->send( buffer, sizeof( struct type1 ) + sizeof( struct type2 ));
我一直是用这种方法的,而且也没有出现过问题.下面是比较详细的代码,各位看看,请多多指教.
// data.h: interface for the CData class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_DATA_H__F849DA10_B160_11CF_BC5B_5254AB4B2098__INCLUDED_)
#define AFX_DATA_H__F849DA10_B160_11CF_BC5B_5254AB4B2098__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "define.h"
class CData
{
public:
CData();
virtual ~CData();
//methods and operations
public:
virtual void Build(); //将数据缓冲区中的数据解码到成员中
virtual BOOL Load(); //填充数据缓冲区
//data members
public:
BYTE type ; //消息类型
BYTE WndIndex; //处理该消息的窗口句柄索引
DWORD flag ; //消息标记
UINT dstPort ; //目的IP地址
UINT dstIP ; //目的端口号
char buffer[Max_Data_Length] ; //数据缓冲区
WORD buf_len ; //数据缓冲区中数据长度
WORD buf_offset; //数据缓冲区中特殊数据的偏移
private:
protected:
};
inline void CopyData(CData *dst,CData *src)
{
for ( int i = 0 ;i < src->buf_len ; i ++ )
dst->buffer[i] = src->buffer[i] ;
dst->type = src->type ;
dst->dstIP = src->dstIP ;
dst->dstPort = src->dstPort ;
dst->buf_len = src->buf_len ;
dst->buf_offset = src->buf_offset ;
dst->WndIndex = src->WndIndex ;
}
#endif // !defined(AFX_DATA_H__F849DA10_B160_11CF_BC5B_5254AB4B2098__INCLUDED_)
/////////////////////////////////////////////////////////////////
// data.cpp: implementation of the CData class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "data.h"
#include "define.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CData::CData()
{
type = MSG_USER_DEFINE ;
WndIndex = 0 ;
dstPort = DEFAULT_DST_PORT ;
dstIP = inet_addr(DEFAULT_DST_IP);
buf_len = 0 ;
buf_offset = 0 ;
WndIndex = -1;
flag = 0 ;
memset(buffer,0,Max_Data_Length);
}
CData::~CData()
{
}
void CData::Build()
{
char *cp = NULL ;
cp = buffer ;
//开头是固定数据
*(BYTE *)cp = type ; //消息类型
cp += sizeof(BYTE) ;
*(BYTE *)cp = WndIndex ; //窗口句柄索引
cp += sizeof(BYTE);
*(DWORD *)cp = flag ; //消息标记
cp += sizeof(DWORD) ;
//以下是附加数据的开始地址
buf_len = cp - buffer ;
buf_offset = cp - buffer ;//用户数据的偏移量
}
BOOL CData::Load()
{
char *cp = buffer ;
type = *(BYTE *)cp ; // 消息类型
cp += sizeof(BYTE) ;
WndIndex = *cp ; //窗口句柄索引
if( WndIndex < 0 && WndIndex >= MaxRecvWndCount )
return FALSE ;
cp += sizeof(WndIndex);
flag = *(DWORD *)cp;
cp += sizeof(DWORD);
buf_offset = cp - buffer ;//用户数据的偏移量
if( buf_offset <= buf_len )return TRUE ;
return FALSE ;
}
//////////////////////////////////////////////////////
class CMsgChat : public CData
{
public:
CMsgChat();
virtual ~CMsgChat() ;
public:
virtual BOOL Load() ;
virtual void Build() ;
public:
WORD srcID ; //source ID
WORD dstID ; //destination ID
WORD nLen ; //发送内容长度
char content[Max_Content_Length]; //内容
};
//////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
// implementation of the CMsgChat class. //
/////////////////////////////////////////////////////////
/********************************************************
Construction CMsgRegist Class's
*********************************************************/
CMsgChat::CMsgChat()
{
nLen = 0 ;
srcID= 0 ;
memset(content,0,Max_Content_Length);
}
CMsgChat::~CMsgChat()
{
}
/********************************************************
Encode CMsgChat Class's buffer
*********************************************************/
void CMsgChat::Build()
{
CData::Build();
char *cp = (char *)(buffer + buf_offset );
*(WORD *)cp = srcID ;
cp += sizeof(WORD) ;
*(WORD *)cp = dstID ;
cp += sizeof(WORD) ;
*(WORD *)cp = nLen ;
cp += sizeof(WORD) ;
memcpy(cp,content,nLen);
cp += nLen ;
buf_len = cp - buffer ;
}
/********************************************************
Decode CMsgChat Class's buffer
*********************************************************/
BOOL CMsgChat::Load()
{
if( !CData::Load() )
return FALSE ;
char *cp = (char *)(buffer + buf_offset );
srcID = *(WORD *)cp ;
cp += sizeof(WORD) ;
dstID = *(WORD *)cp ;
cp += sizeof(WORD) ;
nLen = *(WORD *)cp ;
cp += sizeof(WORD) ;
if(nLen > Max_Content_Length )
memcpy(content,cp,Max_Content_Length);
else memcpy(content,cp,nLen);
cp += nLen ;
if( cp - buffer > buf_len )
return FALSE ;
return TRUE ;
}
Top
7 楼ff324()回复于 2002-12-16 17:17:29 得分 0
楼上几位,特别是西门吹雪,多谢了!结构体传输的问题解决了,不过现在又
有新问题了,怎么用c语言编写的socket传输jpj文件或是几兆的大文件。你们去我的新贴看一下吧。多多谢!!!
http://expert.csdn.net/Expert/topic/1266/1266170.xml?temp=.9910395Top
8 楼anyiflyer(代码在我心中!)回复于 2002-12-18 12:42:52 得分 0
给分啊.Top
9 楼ff324()回复于 2002-12-20 09:53:02 得分 0
我真的已经给分了,奇怪csdn没有显示分值。可能操作有误?我是csdn的新生,初来乍到,人生地不熟?没给成分,楼上几位莫见怪!放心,我会在以后补偿你的,西门大哥。
Top
10 楼anyiflyer(代码在我心中!)回复于 2002-12-26 13:04:34 得分 0
呵呵,没有关系的.CSDN是做的不够好,我都不知道我的分是在什么时候给的,应该显示时间的啊.Top
相关问题
- 高手相助!网络传输结构体的问题。
- windows sockets编程,如何用send()或sendto()传输一个结构体?
- 用ARMV41-UNKNOWN_LINUX-GCC编译出的Socket程序传输结构体出问题,请大家帮忙分析一下
- 结构体中有无符号的整型,怎么转换成char*在网络中传输啊?
- 在结构体里面定义一个大的数组,可是有麻烦了!
- 三层结构大数据量传输问题
- /*================= socket传输中如何传递一个结构? ==================*/
- B/S结构中数据的加密传输的问题
- 没事多讨论:b/s结构软件中数据传输技术
- 没事多讨论:c/s结构软件中数据传输技术




