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 函数,但我不明白为什么?谢谢

当您希望您的代码同时作为 ServerClient 工作时,它被称为 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