【问题标题】:How to send a struct through socket?如何通过套接字发送结构?
【发布时间】:2011-09-25 14:27:29
【问题描述】:

我找到了以下功能,可以发送邮件:

bool sendmail( char * smtpserver, char * from, char * to, char * subject, char * msg ) 
{ 
int         iProtocolPort        = 0; 
char        szSmtpServerName[64] = ""; 
char        szToAddr[64]         = ""; 
char        szFromAddr[64]       = "";
char        szBuffer[4096]       = ""; 
char        szLine[255]          = "";
char        szMsgLine[255]       = ""; 
SOCKET      hServer; 
WSADATA     WSData; 
LPHOSTENT   lpHostEntry; 
LPSERVENT   lpServEntry; 
SOCKADDR_IN SockAddr;  

// Load command-line args 
lstrcpyA( szSmtpServerName, smtpserver );
lstrcpyA( szToAddr, to ); 
lstrcpyA( szFromAddr, from );  

// Attempt to intialize WinSock (1.1 or later)
if ( WSAStartup( MAKEWORD( VERSION_MAJOR, VERSION_MINOR ), &WSData ) ) 
{     
    printf( "\nCannot find Winsock v%d.%d or later", VERSION_MAJOR, VERSION_MAJOR );    
    return false; 
} 
// Lookup email server's IP address. 
lpHostEntry = gethostbyname( szSmtpServerName ); 
if ( !lpHostEntry ) 
{    
    printf( "\nCannot find SMTP mail server %s", szSmtpServerName );     
    return false; 
}  

// Create a TCP/IP socket, no specific protocol 
hServer = socket( PF_INET, SOCK_STREAM, 0 ); 
if ( hServer == INVALID_SOCKET ) 
{     
    printf( "\nCannot open mail server socket!" );    
    return false;
}  

// Get the mail service port 
lpServEntry = getservbyname( "mail", 0 );  

// Use the SMTP default port if no other port is specified
if ( !lpServEntry ) iProtocolPort = htons( IPPORT_SMTP ); 
else iProtocolPort = lpServEntry->s_port;  

// Setup a Socket Address structure 
SockAddr.sin_family = AF_INET; 
SockAddr.sin_port   = iProtocolPort; 
SockAddr.sin_addr   = *( (LPIN_ADDR)*lpHostEntry->h_addr_list );  

// Connect the Socket 
if ( connect( hServer, ( PSOCKADDR ) &SockAddr, sizeof( SockAddr ) ) )
{    
    printf( "\nError connecting to Server socket!" );   
    return false; 
}  

// Receive initial response from SMTP server 
Check( recv( hServer, szBuffer, sizeof( szBuffer ), 0), "recv() Reply" );  

// Send HELO server.com 
sprintf_s( szMsgLine, "HELO %s%s", smtpserver, CRLF ); 
Check( send( hServer, szMsgLine, strlen( szMsgLine ), 0 ), "send() HELO" ); 
Check( recv( hServer, szBuffer, sizeof( szBuffer ), 0 ), "recv() HELO" ); 

// Send MAIL FROM: <sender@mydomain.com> 
sprintf_s( szMsgLine, "MAIL FROM:<%s>%s", from, CRLF );
Check( send( hServer, szMsgLine, strlen( szMsgLine ), 0 ), "send() MAIL FROM" ); 
Check( recv( hServer, szBuffer, sizeof( szBuffer ), 0 ), "recv() MAIL FROM" );  

// Send RCPT TO: <receiver@domain.com>     
sprintf_s( szMsgLine, "RCPT TO:<%s>%s", to, CRLF );    
Check( send( hServer, szMsgLine, strlen( szMsgLine ), 0 ), "send() RCPT TO" );     
Check( recv( hServer, szBuffer, sizeof( szBuffer ), 0 ), "recv() RCPT TO" ); 

// Send DATA 
sprintf_s( szMsgLine, "DATA%s", CRLF ); 
Check( send( hServer, szMsgLine, strlen( szMsgLine ), 0 ), "send() DATA" ); 
Check( recv( hServer, szBuffer, sizeof( szBuffer ), 0 ), "recv() DATA" );  

// Send Subject 
sprintf_s( szBuffer, "Subject: %s\n", subject ); 
Check( send( hServer, szBuffer, strlen( szBuffer ), 0 ), "send() Subject" );  

//Send From 
sprintf_s( szBuffer, "From: %s\n", from );
Check( send( hServer, szBuffer, strlen( szBuffer ), 0 ), "send() From" );  

//Send To 
sprintf_s( szBuffer, "To: %s\n\n", to ); 
Check( send( hServer, szBuffer, strlen( szBuffer ), 0 ), "send() To" ); 

//Check( send( hServer, szMsgLine, strlen( szMsgLine ), 0 ), "send() Attachment" );  
sprintf_s( szMsgLine, "%s%s", msg, CRLF );
Check( send( hServer, szMsgLine, strlen( szMsgLine ), 0 ), "send() message-line" );  

// Send blank line and a period 
sprintf_s( szMsgLine, "%s.%s", CRLF, CRLF );
Check( send( hServer, szMsgLine, strlen( szMsgLine ), 0 ), "send() end-message" );
Check( recv(  hServer, szBuffer, sizeof( szBuffer ), 0 ), "recv() end-message" );  

// Send QUIT 
sprintf_s( szMsgLine, "QUIT%s", CRLF );
Check( send( hServer, szMsgLine, strlen( szMsgLine ), 0 ), "send() QUIT" ); 
Check( recv( hServer, szBuffer, sizeof( szBuffer ), 0 ), "recv() QUIT" );  

// Close server socket and prepare to exit. 
closesocket( hServer );  

WSACleanup();  

return true; 
 } 

我正在进行 SQL 查询,我想通过电子邮件发送结果,但结果可能不止一行。所以我不知道,我怎么能一次发送整个结果。 SQL 查询的结果将存储在一个结构中(但如果有人有更好的想法,那么我正在听:))。所以我的问题是,是否有办法通过电子邮件发送这个结构?或者我如何发送电子邮件中收到的每一行?

谢谢!

【问题讨论】:

  • 您能否先修复您的sendmail() 函数,使其可以发送超过255 个字符的消息?一旦你这样做了,剩下的就像将你的结构转换成你想在电子邮件中发送的任何格式的字符串一样简单。
  • @aroth:我所要做的就是声明更大尺寸的 szMsgLine。那没问题。但是我如何一次发送我的结构?我应该只连接这些行吗?
  • @kampi -- 是的,您必须将结构的内容转换为 C 字符串并发送这些字符串。那是因为另一端的电子邮件处理程序不知道如何解释您的结构。一般规则是结构永远不能跨机器边界移植。
  • @PeteWilson:谢谢。与此同时,我做了这个转换。我只是认为有一种方法可以发送整个结构:)

标签: c windows sockets


【解决方案1】:

在您想发送您的结构的一侧:

 // All sorts of initializations and stuff
 memcpy(yourbuffer,&yourstructure,sizeof(yourbuffer));

另一边:

 // Trivial stuff like receiving your buffer :-)
 memcpy(&yourstructure,yourbuffer,sizeof(yourstructure));

【讨论】:

    【解决方案2】:

    要回答您的第一个问题,如果您想通过套接字发送一个结构,首先您必须对其进行序列化。特别是,整数的字节在目标机器上的顺序可能不同。有很多用于序列化数据的协议,例如 ASN.1 和 JSON。对于 C 结构,最好使用 msgpack 或 protobufs 之类的东西。序列化数据后,您有一个字节数组,可以简单地通过套接字一次发送一个块。一般来说,你也会有一个协议,它可以像这样简单:

    SENDBUF 437\r\n 
    GSUOHD*)*IHENHD{@DNJDPOJDPJONK:ND{D@O LDK?ND(G(OBDO*U|GR(G(DIU:OBD
    

    基本上它是一个命令字符串,后跟这个数据包中的字节数,然后是回车、换行。这是 HTTP、memcache 和许多其他协议使用的典型协议样式。在换行符之后,您将在输入缓冲区的末尾收集接下来的 n 个字节(示例中为 437)。由于许多结构将不止一个数据包,因此您可以使用 BEGIN 和 END 命令,或者您可以简单地关闭套接字以标记结构的结束。

    接收进程会收集字节直到结构体结束,然后反序列化它。

    如果您使用 ZeroMQ 之类的库,这将简化套接字处理,但您仍然需要处理序列化和反序列化结构。

    【讨论】:

      猜你喜欢
      • 2010-11-22
      • 2012-01-20
      • 2016-06-06
      • 1970-01-01
      • 2016-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多