- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试创建一个允许我通过 smtp 与邮件服务器通信的小 C 程序,我创建了这个小程序:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "25"
#define DEFAULT_ADDRESS "smtp.live.com"
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char messaggio[100];
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
while(1){// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(DEFAULT_ADDRESS, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
printf("messaggio: ");
gets(messaggio);
fflush(stdin);
printf("%s\n", messaggio);
// Send an initial buffer
iResult = send( ConnectSocket, messaggio, (int)strlen(messaggio), 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
// Receive until the peer closes the connection
// do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 ){
printf("Bytes received: %d\n", iResult);
printf("messaggio: %s\n", recvbuf);}
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
// } while( iResult > 0 );
// cleanu
closesocket(ConnectSocket);
WSACleanup();
}
system("PAUSE");
return 0;
}
当我启动它时,它会连接到 smtp 服务器,然后发送消息(例如 Hello 消息)并收到 220 回复代码,这意味着服务已准备就绪。当我继续键入命令时,它会继续向我发送 220 代码而不继续,而当我错过键入命令时,它只会崩溃。
有谁能帮帮我吗?
附注我不相信代码,我只是修改了一些微软的套接字客户端文档来与 smtp.live.com 交谈,显然它确实有效......
[编辑] x2:
好的,感谢 Remy Lebeau,我显然设法解决了这些问题,希望这是最后一个。
编辑代码:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "25"
#define DEFAULT_ADDRESS "smtp.live.com"
int __cdecl main(int argc, char **argv){
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char messaggio[100];
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
int success = 1;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData); // Initialize Winsock
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
iResult = getaddrinfo(DEFAULT_ADDRESS, DEFAULT_PORT, &hints, &result); // Resolve the server address and port
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) { // Attempt to connect to an address until one succeeds
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); //Connect to server.
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
while(success){
printf("messaggio: ");
scanf(" %[^\n]", messaggio);
printf("%s\n", messaggio);
iResult = send( ConnectSocket, strcat(messaggio,"\r\n"), (int)strlen(messaggio)+2, 0 ); //Send an initial buffer
if (iResult < 0 || iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
system("PAUSE");
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
do{ //riceve tutto il possibile dal server
iResult = recv(ConnectSocket, recvbuf, recvbuflen-1, 0);
recvbuf[iResult]='\0';
if ( iResult > 0 ){
printf("Bytes received: %d\n", iResult);
printf("messaggio: %s\n", recvbuf);
}
else{
printf("recv failed with error: %d\n", WSAGetLastError());
success=0;
}
}while(recvbuf[iResult-3]=='\r'&& recvbuf[iResult-2]=='\n');
printf("stop receive\n");
}
iResult = shutdown(ConnectSocket, SD_SEND);
closesocket(ConnectSocket);
WSACleanup();
system("PAUSE");
return 0;
}
现在它确实接受了我的命令并且它确实响应了,我做 helo
, mail from: <mail>
和 to: <mail>
此时它说:“530(身份验证问题代码)必须先发出 STARTTLS 命令。
有办法解决吗?我必须对我发送的命令进行编码,有没有办法用 winsock 做到这一点?
我是不是几乎明白了问题的要点,还是这不是问题所在?
最佳答案
对于 SMTP 客户端,您的代码逻辑不完整。
TCP 是一个字节流。无法保证您能够在单个 send()
调用中发送整个命令,或者您能够在单个 recv()< 中接收到整个响应
调用。你必须继续发送,直到你没有什么可发送的,你必须继续阅读,直到没有什么可读的。对于 SMTP,这意味着当您遇到终止每行的 \r\n
时。
一旦您的底层套接字 I/O 开始工作,您仍然没有实现实际的 SMTP 协议(protocol)。您只是在服务器上抛出任意数据并读取它返回的任意数据。 SMTP 有您需要考虑的规则。例如,SMTP 服务器在接受命令之前发送问候语。你不是在读那个问候语。此外,SMTP 响应可能有 1 行或多行,因此您必须单独解析每一行(格式在 RFC 5321 中概述)以发现需要读取多少行。继续阅读,直到遇到响应的最后一行。在完全读取上一个响应之前不要发送下一个命令(除非你想实现 SMTP pipelining ,我不会在这里讨论)。
至于“必须首先发出 STARTTLS 命令”错误,这是不言自明的。您通过不安全的连接发送了 SMTP 命令,但服务器希望通过安全连接发送该命令(例如发送包含纯文本身份验证凭据的 AUTH
命令时)。 STARTTLS
命令用于激活新的 SSL/TLS session 以保护当前不安全的连接。
您可以使用像 OpenSSL 这样的库,或类似 Microsoft 的 API SChannel , 在套接字之上实现实际的 SSL/TLS。这超出了这个问题的范围。如果您在实现 SSL/TLS 方面需要帮助,有很多关于该主题的书籍和教程。
综上所述,请尝试更像这样的方法:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#pragma command(lib, "mswsock.lib")
//#pragma command(lib, "advapi32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "25"
#define DEFAULT_ADDRESS "smtp.live.com"
char *recvbuf = NULL;
int recvbuflen = 0;
int recvbufused = 0;
int sendData(SOCKET s, char *buffer, int buflen)
{
int iResult;
while (buflen > 0)
{
// TODO: if the connection is secure, encrypt the data being sent...
iResult = send(s, buffer, buflen, 0);
if (iResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
return -1;
}
buffer += iResult;
buflen -= iResult;
}
return 0;
}
int sendLine(SOCKET s, char *line)
{
int iResult = sendData(s, line, strlen(line));
if (iResult == 0)
iResult = sendData(s, "\r\n", 2);
return iResult;
}
int readLine(SOCKET s, char **line)
{
char buf[DEFAULT_BUFLEN];
int iResult;
int offset = 0, len, total;
char *p;
*line = NULL;
do
{
// check if the line terminator is already in the buffer
p = memchr(recvbuf+offset, '\n', recvbufused-offset);
if (p != NULL)
{
++p;
total = (p - recvbuf);
// check if the line terminator is actually "\r\n"
len = total - 1;
if ((len > 0) && (recvbuf[len-1] == '\r'))
--len;
// extract the line and remove it from the buffer
*line = malloc(len+1);
if (*line == NULL)
{
printf("Unable to allocate memory! Bytes: %d\n", len+1);
return -1;
}
memcpy(*line, recvbuf, len);
(*line)[len] = 0;
memmove(recvbuf, recvbuf+total, recvbufused-total);
recvbufused -= total;
printf("%s\n", *line);
return len;
}
// line terminator is not in the buffer, keep reading
// do not search the buffer that was already searched
offset = recvbufused;
// read more data from the socket
iResult = recv(s, buf, sizeof(buf), 0);
if (iResult <= 0)
{
if (iResult == 0)
printf("server closed the connection\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
break;
}
// TODO: if the connection is secure, decrypt the data that was received...
// if the buffer is too small for the new data, grow it
if ((recvbufused+iResult) > recvbuflen)
{
len = (recvbufused+iResult) + DEFAULT_BUFLEN;
p = realloc(recvbuf, len);
if (p == NULL)
{
printf("Unable to allocate memory! Bytes: %d\n", len);
break;
}
recvbuf = p;
recvbuflen = len;
}
// now add the data to the buffer
memcpy(recvbuf+recvbufused, buf, iResult);
recvbufused += iResult;
}
while (1);
return -1;
}
int readResponse(SOCKET s)
{
char *line, term[5];
int len, code = 0;
// read the first line
len = readLine(s, &line);
if (len == -1)
return -1;
// check if the response has multiple lines
if ((len > 3) && (line[3] == '-'))
{
// keep reading until the last line is received
memcpy(term, line, 3);
term[3] = ' ';
term[4] = '\0';
do
{
free(line);
len = readLine(s, &line);
if (len == -1)
return -1;
}
while ((len > 3) && (strncmp(line, term, 4) != 0));
}
// now extract the response code and return it
if (len > 3) line[3] = '\0';
code = strtol(line, NULL, 10);
free(line);
if (code == 0)
return -1;
return code;
}
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo hints, *result, *ptr;
char messaggio[100];
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(DEFAULT_ADDRESS, DEFAULT_PORT, &hints, &result);
if (iResult != 0)
{
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL; ptr=ptr->ai_next)
{
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET)
{
printf("socket failed with error: %ld\n", WSAGetLastError());
break;
}
//Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, ptr->ai_addrlen);
if (iResult == 0)
break;
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET)
{
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
printf("Connected to server\n");
// read the greeting
iResult = readResponse(ConnectSocket);
if (iResult == 220)
{
do
{
// ask the user for a command
printf("messaggio: ");
if (!fgets(messaggio, sizeof(messaggio), stdin))
break;
// remove the line terminator if present
iResult = strlen(messaggio);
if ((iResult > 0) && (messaggio[iResult-1] == '\n'))
messaggio[iResult-1] = '\0';
// send the command
iResult = sendLine(ConnectSocket, messaggio);
if (iResult == -1)
break;
// read the response
iResult = readResponse(ConnectSocket);
if (iResult == -1)
break;
// need to stop now?
if (strcmp(messaggio, "QUIT") == 0)
break;
// need to turn on SSL/TLS now?
if ((strcmp(messaggio, "STARTTLS") == 0) && (iResult == 220))
{
// TODO: activate SSL/TLS, stop if failed...
}
}
while(1);
}
shutdown(ConnectSocket, SD_SEND);
do
{
iResult = recv(ConnectSocket, messaggio, sizeof(messaggio), 0);
}
while (iResult > 0);
closesocket(ConnectSocket);
WSACleanup();
free(recvbuf);
system("PAUSE");
return 0;
}
关于c - 尝试使用 C 程序通过 SMTP 与电子邮件服务器通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37973097/
大多数语言都支持双向进程通信。例如,在 Python 中,我可以(草率地)执行以下操作: >>> from subprocess import * >>> p = Popen('nslookup',
致力于使用 C++ 在 arduino 和 PC (Win 7) 之间进行通信。使用 WriteFile 和 ReadFile 创建通信或简单地发送或接收数据没有问题。但是当我想以某种方式“协调”沟通
我们正在开发一个基于微服务的应用程序。它们将使用 Helm Package Manager 部署到 kubernetes,并且它们都存储了自己的存储库和 helm chart。以下是我们微服务的名称。
我正在开发一个大型 MVVM 应用程序。我为此使用了 MVVM 轻量级工具包。该应用程序就像一个带有后退和前进按钮的网络浏览器。主视图是一个用户控件。我在主视图用户控件中放置了后退和前进按钮。主视图又
我在 java 和 freepascal(lazarus) 应用程序之间的通信有问题。我使用套接字。它们正确连接。一切都很顺利,直到我想从一个应用程序向另一个应用程序发送一些东西。在java而不是“a
我已经使用客户端套接字和服务器套接字使用C#编写了群聊。 当我使用VS 2017在自己的PC中运行程序(服务器和客户端)时,客户端和服务器之间的通信工作正常。 当我在笔记本电脑中运行客户端程序,并在自
Kubernetes 中两个不同 Pod 之间的通信是如何发生的? 就我而言,我有两个 Pod:前端和后端,它们都有不同的容器。 我希望我的前端 pod 与后端 pod 通信,但我不想使用后端 pod
我正在尝试在浏览器中嵌入的 flash 实例与在 C# WinForms 应用程序中运行的 flash 实例之间进行通信...我收到一个编译错误,内容为: 1119 Access of possibl
鉴于网络上缺乏信息,请问一个问题:我要在 Android 中创建一个应用程序,使用一个数据库应用程序 rails 。为此,我需要一个手动 session 。所以如果有人准备好了示例/教程显示通信 an
我正在编写一个应用程序,它将通过 MySQL 数据库对用户进行身份验证。我已经用 Java (android) 编写了它,但现在正在移植到 Windows 手机。 PHP 文件使用 $get 然后回显
是否可以通过互联网在两个不同设备上的两个不同应用程序之间建立通信。我想从设备 A 上的应用程序点击一个设备 B 上的应用程序,然后从设备 B 上的应用程序获取数据到设备 A 上的应用程序。如果可能,如
这是脚本: 它被放置在其他网站上。 com 并显示一个 iframe。如果有人点击 iframe 中的某个内容,脚本应该将一个 div 写入 othersite 。 com. 所以我的问题是如何做到
你好我是 php 的新手,我用 c++ 编写了整个代码并想在 php 中使用这段代码。所以我为我的代码制作了 dll 以使用它。但是我不能在 php 中使用这个 dll,可以谁能给我完整的代码来使用
我确定之前已经有人问过(并回答过)此类问题,所以如果是这样,请将我链接到之前的讨论... 在 C++ 中,假设我有一个 ClassA 类型的对象,其中包含一个 ClassB 类型的私有(private
我正在尝试使用 ATmega32 进行串行通信。首先,我使用 RS232,使用 USB-to-RS232 建立使用串行终端的接收和传输(在我的例子中是 tera 术语)。无论我从串行终端 Atmega
我找不到适用于 Ruby 的 SSL 实现。 我的部分项目需要服务器和客户端之间的安全通信链接,我希望为此使用 SSL 以创建安全 session 。 谢谢 最佳答案 如果你使用 Ruby 1.9.x
我正在尝试在客户端/服务器之间进行 SSL 通信。 到目前为止,我已经从 keystore 创建了 java.security.cert.X509Certificate。接下来我应该怎么做才能使这次沟
我在与 Windows 上的 USB 设备 通信时遇到问题。我不能使用 libusb 或 WinUSB,因为我有一个特定的驱动程序(Silabs USB 到 UART,这是一个 USB 到串口的桥接器
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我发现 xcom 实际上是将数据写入数据库并从其他任务中提取数据。我的数据集很大,将其腌制并写入数据库会导致一些不必要的延迟。有没有办法在不使用 xcom 的情况下在同一 Airflow Dag 中的
我是一名优秀的程序员,十分优秀!