用socket发送结构,如何还原

allforly 2003-09-07 06:31:28
client:
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <winsock2.h>
typedef struct{
char arcPrefix[9];
char cComma1;
char arcPhone[11];
char cComma2;
char arcPortNum[11];
char cComma3;
char arcMsg[140];
}GameRecvPacket;

using namespace std;
#define IP_Port 5003
#define IP_Addr TEXT("192.168.0.1")
#define MAX_MESSAGE_LENGTH 1024

int main(int argc,char *argv[]){
SOCKET sclient;
struct sockaddr_in server;
int namelen,pklen;
int status,ret;
char buf[MAX_MESSAGE_LENGTH];
WSADATA wsd;
GameRecvPacket RecvPtr;
if((status=WSAStartup(MAKEWORD(2,2),&wsd))!=0){
perror("wsastartup() failed:");
system("pause");
return 0;
}
if((sclient=socket(AF_INET,SOCK_STREAM,0))< 0){
perror("socket failed :");
system("pause");
return 0;
}
ZeroMemory(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(IP_Port);
server.sin_addr.s_addr=inet_addr(IP_Addr);
if(connect(sclient,(struct sockaddr *)&server,sizeof(server))<0){
perror("connect() failed :");
printf("%d\n",WSAGetLastError());
system("pause");
return 0;
}
namelen=sizeof(sclient);
for(ret=0;ret<10;ret++){
strcpy(RecvPtr.arcPrefix, "receive ");
RecvPtr.cComma1 = ',';
strcpy(RecvPtr.arcPhone, "3343232");
RecvPtr.cComma2 = ',';
strcpy(RecvPtr.arcPortNum, "5503 ");
RecvPtr.cComma3 = ',';
strcpy(RecvPtr.arcMsg, "hello");
send(sclient, (char *)&RecvPtr, sizeof(GameRecvPacket), 0);
printf("send() context -> '%s'\n", (char *)&RecvPtr);
if((pklen=recv(sclient,buf,sizeof(buf),0))<0){
perror("recv() failed:");
break;
}else if(pklen==0){
printf("recv():return FAILED,connected is shut down\n");
break;
}else{
printf("the pktlen is %d\n",pklen);
printf("recv():return success\npacket length=%d and the context is %s\n", pklen, buf);
}
Sleep(10);
}
closesocket(sclient);
WSACleanup();
printf("server ended successfully\n");
system("pause");
return 0;
}
...全文
38 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
liao2001 2004-03-22
  • 打赏
  • 举报
回复
>>回复人: liao2001(知之为知之,不知为不知。。。) ( ) 信誉:100 2004-03-18 >>10:08:00 得分:0

>>网络通信收发结构体?
>>这种方式不可取,即便你的结构体中都是字符类型。

>>回复人: HunterForPig(留着口水的猪) ( ) 信誉:100 2004-03-20 07:03:00 得分:0

>>楼上能说具体点吗,为何不可取

如果结构体中存在非字符类型时,我们可能就得考虑主机字节序的问题,还得考虑结构体对齐问题,相关资料可以自己上网搜索。
针对楼主的这个例子,结构体中都是字符类型,就目前我们所常用的编译器来说,是可以用结构体收发的,只是这种方法只能用于特例,这就是我说“不可取”的原因。
HunterForPig 2004-03-20
  • 打赏
  • 举报
回复
楼上能说具体点吗,为何不可取
gaoxianfeng 2004-03-20
  • 打赏
  • 举报
回复
初始化
memset((void*)&your_val/*GameRecvPacket结构类型*/,0,sizeof(GameRecvPacket));
数据通信tcp的 是面向连接 对应用来说是接收数据时有序的 发的abc 收到的必然是abc 但有可能分几次收到 最好在发送数据的时候 带上长度依据长度分析
liao2001 2004-03-18
  • 打赏
  • 举报
回复
网络通信收发结构体?
这种方式不可取,即便你的结构体中都是字符类型。
boxban 2004-03-18
  • 打赏
  • 举报
回复
你的处理流程问题不大,关键问题在于client端对结构体的赋值部分。

结构定义如下:
typedef struct{
char arcPrefix[9];
char cComma1;
char arcPhone[11];
char cComma2;
char arcPortNum[11];
char cComma3;
char arcMsg[140];
}GameRecvPacket;

你的赋值语句
strcpy(RecvPtr.arcPrefix, "receive ");
中源字符串的长度为9(含空格),而arcPrefix的大小仅为9,而strcpy会自动在拷贝完这些字符之后添加一个“结尾零”,由于arcPrefix本身已经填满,那个结尾零就填入下一个字节,正好是cComma1的位置,因此,上句执行完后,cComma1 == '\0';
接着你又重新给cComma1赋值
RecvPtr.cComma1 = ',';
从而覆盖掉了arcPrefix的结尾零。

arcPhone、arcPortNum也是这样的问题:strcpy中源字符串的长度恰好等于缓冲区的大小,没有为结尾零留出位置。从而导致整个结构体仅在arcMsg中含有一个结尾零。而C/C++在打印字符串时是以结尾零作为字符串的终结标志,因此当你在服务器端收下这个结构体并试图打印其内容时,总是打印到hello才结束。这不是服务器的错,而是client的错。

修改的办法很简单,给arcPrefix等缓冲区添加一个存放结尾零的空间,如下:
typedef struct{
char arcPrefix[10];
char cComma1;
char arcPhone[12];
char cComma2;
char arcPortNum[12];
char cComma3;
char arcMsg[140];
}GameRecvPacket;


另外,下面一句赋值好像没有问题,
strcpy(RecvPtr.arcPhone, "3343232");
不知为什么会出现不该出现的输出?
tianyxy 2004-03-18
  • 打赏
  • 举报
回复
强制类型转换呀类型
allforly 2003-09-07
  • 打赏
  • 举报
回复
server:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock2.h>

using namespace std;

typedef struct{
char arcPrefix[9];
char cComma1;
char arcPhone[11];
char cComma2;
char arcPortNum[11];
char cComma3;
char arcMsg[140];
}GameRecvPacket;

#define USERPORT 5003
#define HOST_IP_ADDR TEXT("192.168.0.1")

int main(){
char buf[1024];
SOCKET ServerSocket,ClientSocket;
struct sockaddr_in client;
struct sockaddr_in server;
int namelen,recvlen;
int status;
WSADATA wsd;
GameRecvPacket *RecvPtr;
if((status=WSAStartup(MAKEWORD(2,2),&wsd))!=0){
perror("wsastartup() failed:");
}else if((ServerSocket = socket(AF_INET,SOCK_STREAM,0))< 0){
perror("socket failed :");
}else{
server.sin_family = AF_INET;
server.sin_port = htons(USERPORT);
server.sin_addr.s_addr = htons(INADDR_ANY);
if(bind(ServerSocket,(struct sockaddr *)&server,sizeof(server))<0)
{
perror("bind failed -> ");
exit(2);
}
if(listen(ServerSocket,4)!=0)
{
perror("listen failed -> ");
exit(3);
}
while(1){
namelen = sizeof(client);
if((ClientSocket = accept(ServerSocket,(struct sockaddr*)&client,&namelen))==-1){
perror("accept failed -> ");
exit(4);
}
printf("accept successful\n");
for(;;){
if((recvlen = recv(ClientSocket,buf,sizeof(GameRecvPacket),0))<0){
perror("recv failed -> ");
break;
}else if(recvlen==0){
printf("recv return failed, connect is shut down\n");
break;
}else{
RecvPtr = (GameRecvPacket *)buf;
printf("recv return success, packet length = %d, context is '%s'\n", recvlen, buf);
cout<<"Prefix -> "<<RecvPtr->arcPrefix<<endl;
cout<<"Phone -> "<<RecvPtr->arcPhone<<endl;
cout<<"Prot -> "<<RecvPtr->arcPortNum<<endl;
cout<<"Msg -> "<<RecvPtr->arcMsg<<endl;
free(RecvPtr);
}
Sleep(1);
if(send(ClientSocket,buf,sizeof(buf),0)<0){
perror("send failed -> ");
break;
}else
printf("send return success, packet length is %d\n",recvlen);
}
}
closesocket(ClientSocket);
closesocket(ServerSocket);
}
return 0;
}

server端输出:
send return success, packet length is 174
recv return success, packet length = 174, context is 'receive ,3343232,5503
,hello'
Prefix -> receive ,3343232,5503 ,hello
Phone -> 3343232,5503 ,hello
Prot -> 5503 ,hello
Msg -> hello

这是怎么回事情呢?

69,368

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧