C: 在绑定前使用写函数时出错
C: Error when using write function before bind
我是 C 的新手,在使用套接字时遇到了一些问题。我正在创建一个既是服务器又是客户端的程序(我真的不知道这是否可以接受,但出于教育目的)。我想让程序做的是:当程序(A)是运行时,它应该向某人(程序B)发送一些字符串,然后成为服务器。在成为服务器时,我的意思是它应该监听并接受传入的连接。这是我的程序 A 的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, number;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = 0;
serv_addr.sin_port = htons(portno);
connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
number = write(sockfd,"Hey!",strlen("Hey!"));
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
sockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (sockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(sockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(sockfd);
return 0;
}
和程序 B 的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = 0;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
sockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (sockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(sockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(sockfd);
return 0;
}
当我首先 运行 程序 B 和 A 时。接收到字符串 Hey 但程序 A 崩溃并在绑定时给出错误 ERROR : 无效参数。此错误来自 bind
函数,但我不明白为什么?谢谢
当您希望您的代码同时作为 Server
和 Client
工作时,它被称为 TCP Proxy
。我希望 this link 能帮助你实现它。
A TCP proxy
是充当客户端和另一台服务器之间的中介的服务器。 Client
建立到 TCP proxy
服务器的连接,然后服务器建立到目标服务器的连接。
这是设计使然!您必须决定哪个程序是服务器端(调用 bind()
),哪个程序是客户端(调用 connect()
)。这与读写无关,连接是双向的。但附带一提,一个体面的服务器应该能够 accept()
ing 多个连接......传统上这是通过分叉完成的,根据您的情况有更好的方法。
绑定失败的原因有很多。
首先,套接字已经连接,因此它已经绑定到一个本地地址,即使您没有指定它。当你调用 connect 时,系统会自动将套接字绑定到一个本地空闲地址。所以 bind
调用应该会失败。 bind
手册页给出了这个可能的错误
[EINVAL] socket已经绑定地址,协议不支持绑定新地址...
这还不是全部。程序 B 已经在同一地址上侦听。所以即使你关闭并重新打开套接字,绑定调用仍然会失败:
[EADDRINUSE]指定的地址已被使用。
如果你不等待 B 关闭它自己的套接字
这里的问题不在于 C 编程,而在于 TCP/IP 网络。域 AF_INET 中的套接字是 2 个端点之间的网络双向连接,由 IP 地址和端口号组成。一对(地址、端口)不能同时打开多次。因为这个地址是用来知道数据包应该送到哪里的,所以if必须是唯一的。
所以你应该:
- 关闭并重新打开套接字
- 等待一段时间(一秒应该足够)让 B 在绑定到服务器地址之前关闭其套接字
最后但并非最不重要的一点:
在向套接字写入内容后立即关闭套接字是错误且危险的:取决于网络配置、消息大小等。关闭可能会破坏可能尚未发送的部分最后写入。当你在环回接口上使用短消息时,我认为它不会发生在这里。但是如果你想掌握socket的用法,你可以试试graceful shutdown
我是 C 的新手,在使用套接字时遇到了一些问题。我正在创建一个既是服务器又是客户端的程序(我真的不知道这是否可以接受,但出于教育目的)。我想让程序做的是:当程序(A)是运行时,它应该向某人(程序B)发送一些字符串,然后成为服务器。在成为服务器时,我的意思是它应该监听并接受传入的连接。这是我的程序 A 的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, number;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = 0;
serv_addr.sin_port = htons(portno);
connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
number = write(sockfd,"Hey!",strlen("Hey!"));
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
sockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (sockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(sockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(sockfd);
return 0;
}
和程序 B 的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = 0;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
sockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (sockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(sockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(sockfd);
return 0;
}
当我首先 运行 程序 B 和 A 时。接收到字符串 Hey 但程序 A 崩溃并在绑定时给出错误 ERROR : 无效参数。此错误来自 bind
函数,但我不明白为什么?谢谢
当您希望您的代码同时作为 Server
和 Client
工作时,它被称为 TCP Proxy
。我希望 this link 能帮助你实现它。
A TCP proxy
是充当客户端和另一台服务器之间的中介的服务器。 Client
建立到 TCP proxy
服务器的连接,然后服务器建立到目标服务器的连接。
这是设计使然!您必须决定哪个程序是服务器端(调用 bind()
),哪个程序是客户端(调用 connect()
)。这与读写无关,连接是双向的。但附带一提,一个体面的服务器应该能够 accept()
ing 多个连接......传统上这是通过分叉完成的,根据您的情况有更好的方法。
绑定失败的原因有很多。
首先,套接字已经连接,因此它已经绑定到一个本地地址,即使您没有指定它。当你调用 connect 时,系统会自动将套接字绑定到一个本地空闲地址。所以 bind
调用应该会失败。 bind
手册页给出了这个可能的错误
[EINVAL] socket已经绑定地址,协议不支持绑定新地址...
这还不是全部。程序 B 已经在同一地址上侦听。所以即使你关闭并重新打开套接字,绑定调用仍然会失败:
[EADDRINUSE]指定的地址已被使用。
如果你不等待 B 关闭它自己的套接字
这里的问题不在于 C 编程,而在于 TCP/IP 网络。域 AF_INET 中的套接字是 2 个端点之间的网络双向连接,由 IP 地址和端口号组成。一对(地址、端口)不能同时打开多次。因为这个地址是用来知道数据包应该送到哪里的,所以if必须是唯一的。
所以你应该:
- 关闭并重新打开套接字
- 等待一段时间(一秒应该足够)让 B 在绑定到服务器地址之前关闭其套接字
最后但并非最不重要的一点:
在向套接字写入内容后立即关闭套接字是错误且危险的:取决于网络配置、消息大小等。关闭可能会破坏可能尚未发送的部分最后写入。当你在环回接口上使用短消息时,我认为它不会发生在这里。但是如果你想掌握socket的用法,你可以试试graceful shutdown