【问题标题】:block same address in winsock在winsock中阻止相同的地址
【发布时间】:2014-01-23 18:52:29
【问题描述】:

我想使用Winsock构建一个没有服务器的聊天应用程序(我不知道叫什么可能是点对点聊天)。

我刚刚从这两个源代码中学到了:

//==================================================== file = udpServer.c =====
//=  A message "server" program to demonstrate sockets programming            =
//=============================================================================
//=  Notes:                                                                   =
//=    1) This program conditionally compiles for Winsock and BSD sockets.    =
//=       Set the initial #define to WIN or BSD as appropriate.               =
//=    2) This program serves a message to program udpClient running on       =
//=       another host.                                                       =
//=    3) The steps #'s correspond to lecture topics.                         =
//=---------------------------------------------------------------------------=
//=  Example execution: (udpServer and udpClient running on host 127.0.0.1)   =
//=    Waiting for recvfrom() to complete...                                  =
//=    IP address of client = 127.0.0.1  port = 55476)                        =
//=    Received from client: Test message from CLIENT to SERVER               =
//=---------------------------------------------------------------------------=
//=  Build: bcc32 udpServer.c or cl udpServer.c wsock32.lib for Winsock       =
//=         gcc udpServer.c -lsocket -lnsl for BSD                            =
//=---------------------------------------------------------------------------=
//=  Execute: udpServer                                                       =
//=---------------------------------------------------------------------------=
//=  Author: Ken Christensen                                                  =
//=          University of South Florida                                      =
//=          WWW: http://www.csee.usf.edu/~christen                           =
//=          Email: christen@csee.usf.edu                                     =
//=---------------------------------------------------------------------------=
//=  History:  KJC (08/02/08) - Genesis (from server1.c)                      =
//=            KJC (09/07/09) - Minor clean-up                                =
//=            KJC (09/22/13) - Minor clean-up to fix warnings                =
//=============================================================================
#define  WIN                // WIN for Winsock and BSD for BSD sockets

//----- Include files --------------------------------------------------------
#include <stdio.h>          // Needed for printf()
#include <string.h>         // Needed for memcpy() and strcpy()
#include <stdlib.h>         // Needed for exit()
#ifdef WIN
  #include <windows.h>      // Needed for all Winsock stuff
#endif
#ifdef BSD
  #include <sys/types.h>    // Needed for sockets stuff
  #include <netinet/in.h>   // Needed for sockets stuff
  #include <sys/socket.h>   // Needed for sockets stuff
  #include <arpa/inet.h>    // Needed for sockets stuff
  #include <fcntl.h>        // Needed for sockets stuff
  #include <netdb.h>        // Needed for sockets stuff
#endif

//----- Defines --------------------------------------------------------------
#define  PORT_NUM   1050    // Arbitrary port number for the server

//===== Main program =========================================================
int main()
{
#ifdef WIN
  WORD wVersionRequested = MAKEWORD(1,1);       // Stuff for WSA functions
  WSADATA wsaData;                              // Stuff for WSA functions
#endif
  int                  server_s;        // Server socket descriptor
  struct sockaddr_in   server_addr;     // Server Internet address
  struct sockaddr_in   client_addr;     // Client Internet address
  struct in_addr       client_ip_addr;  // Client IP address
  int                  addr_len;        // Internet address length
  char                 out_buf[4096];   // Output buffer for data
  char                 in_buf[4096];    // Input buffer for data
  int                  retcode;         // Return code

#ifdef WIN
  // This stuff initializes winsock
  WSAStartup(wVersionRequested, &wsaData);
#endif

  // >>> Step #1 <<<
  // Create a socket
  //   - AF_INET is Address Family Internet and SOCK_DGRAM is datagram
  server_s = socket(AF_INET, SOCK_DGRAM, 0);
  if (server_s < 0)
  {
    printf("*** ERROR - socket() failed \n");
    exit(-1);
  }

  // >>> Step #2 <<<
  // Fill-in my socket's address information
  server_addr.sin_family = AF_INET;                 // Address family to use
  server_addr.sin_port = htons(PORT_NUM);           // Port number to use
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // Listen on any IP address
  retcode = bind(server_s, (struct sockaddr *)&server_addr,
    sizeof(server_addr));
  if (retcode < 0)
  {
    printf("*** ERROR - bind() failed \n");
    exit(-1);
  }

  // >>> Step #3 <<<
  // Wait to receive a message from client
  printf("Waiting for recvfrom() to complete... \n");
  addr_len = sizeof(client_addr);
  retcode = recvfrom(server_s, in_buf, sizeof(in_buf), 0,
    (struct sockaddr *)&client_addr, &addr_len);
  if (retcode < 0)
  {
    printf("*** ERROR - recvfrom() failed \n");
    exit(-1);
  }

  // Copy the four-byte client IP address into an IP address structure
  memcpy(&client_ip_addr, &client_addr.sin_addr.s_addr, 4);

  // Print an informational message of IP address and port of the client
  printf("IP address of client = %s  port = %d) \n", inet_ntoa(client_ip_addr),
    ntohs(client_addr.sin_port));

  // Output the received message
  printf("Received from client: %s \n", in_buf);

  // >>> Step #4 <<<
  // Send to the client using the server socket
  strcpy(out_buf, "This is a reply message from SERVER to CLIENT");
  retcode = sendto(server_s, out_buf, (strlen(out_buf) + 1), 0,
    (struct sockaddr *)&client_addr, sizeof(client_addr));
  if (retcode < 0)
  {
    printf("*** ERROR - sendto() failed \n");
    exit(-1);
  }

  // >>> Step #5 <<<
  // Close all open sockets
#ifdef WIN
  retcode = closesocket(server_s);
  if (retcode < 0)
  {
    printf("*** ERROR - closesocket() failed \n");
    exit(-1);
  }
#endif
#ifdef BSD
  retcode = close(server_s);
  if (retcode < 0)
  {
    printf("*** ERROR - close() failed \n");
    exit(-1);
  }
#endif

#ifdef WIN
  // This stuff cleans-up winsock
  WSACleanup();
#endif

  // Return zero and terminate
  return(0);
}

//=========================================== file = udpClientBroadcast.c =====
//=  A message "client" program to demonstrate sockets programming            =
//=   - This is udpClient.c modified to use broadcast                         =
//=============================================================================
//=  Notes:                                                                   =
//=    1) This program conditionally compiles for Winsock and BSD sockets.    =
//=       Set the initial #define to WIN or BSD as appropriate.               =
//=    2) This program needs udpServer to be running on another host.         =
//=       Program udpServer must be started first.                            =
//=---------------------------------------------------------------------------=
//=  Example execution: (udpServer and udpClientBroadcast on host 127.0.0.1)  =
//=    Received from server: This is a reply message from SERVER to CLIENT    =
//=---------------------------------------------------------------------------=
//=  Build: Windows: Borland: bcc32 udpClientBroadcast.c                      =
//=                  Visual C cmd line: cl udpClientBroadcast.c wsock32.lib   =
//=                  MinGW: gcc udpClientBroadcast.c -lws2_32                 =
//=         Unix: gcc udpClientBroadcast.c -lnsl -o udpClientBroadcast        =
//=---------------------------------------------------------------------------=
//=  Execute: udpClientBroadcast                                              =
//=---------------------------------------------------------------------------=
//=  Author: Ken Christensen                                                  =
//=          University of South Florida                                      =
//=          WWW: http://www.csee.usf.edu/~christen                           =
//=          Email: christen@csee.usf.edu                                     =
//=---------------------------------------------------------------------------=
//=  History:  KJC (04/10/10) - Genesis (from udpClient.c)                    =
//=============================================================================
#define  WIN                // WIN for Winsock and BSD for BSD sockets

//----- Include files ---------------------------------------------------------
#include <stdio.h>          // Needed for printf()
#include <string.h>         // Needed for memcpy() and strcpy()
#ifdef WIN
  #include <windows.h>      // Needed for all Winsock stuff
#endif
#ifdef BSD
  #include <sys/types.h>    // Needed for sockets stuff
  #include <netinet/in.h>   // Needed for sockets stuff
  #include <sys/socket.h>   // Needed for sockets stuff
  #include <arpa/inet.h>    // Needed for sockets stuff
  #include <fcntl.h>        // Needed for sockets stuff
  #include <netdb.h>        // Needed for sockets stuff
#endif

//----- Defines ---------------------------------------------------------------
#define  PORT_NUM           1050  // Port number used

//===== Main program ==========================================================
void main(void)
{
#ifdef WIN
  WORD wVersionRequested = MAKEWORD(1,1);       // Stuff for WSA functions
  WSADATA wsaData;                              // Stuff for WSA functions
#endif
  int                  client_s;        // Client socket descriptor
  struct sockaddr_in   server_addr;     // Server Internet address
  int                  addr_len;        // Internet address length
  char                 out_buf[4096];   // Output buffer for data
  char                 in_buf[4096];    // Input buffer for data
  int                  retcode;         // Return code
  int                  iOptVal;         // Socket option value
  int                  iOptLen;         // Socket option length

#ifdef WIN
  // This stuff initializes winsock
  WSAStartup(wVersionRequested, &wsaData);
#endif

  // Create a socket
  client_s = socket(AF_INET, SOCK_DGRAM, 0);
  if (client_s < 0)
  {
    printf("*** ERROR - socket() failed \n");
    exit(-1);
  }

  // Fill-in server socket's address information
  server_addr.sin_family = AF_INET;                 // Address family to use
  server_addr.sin_port = htons(PORT_NUM);           // Port num to use
  server_addr.sin_addr.s_addr = inet_addr(INADDR_ANY); // Need this for Broadcast

  // Set socket to use MAC-level broadcast
  iOptVal = 1;
  iOptLen = sizeof(int);
  setsockopt(client_s, SOL_SOCKET, SO_BROADCAST, (char*)&iOptVal, iOptLen);

  // Assign a message to buffer out_buf
  strcpy(out_buf, "Test message from CLIENT to SERVER");

  // Now send the message to server.
  retcode = sendto(client_s, out_buf, (strlen(out_buf) + 1), 0,
    (struct sockaddr *)&server_addr, sizeof(server_addr));
  if (retcode < 0)
  {
    printf("*** ERROR - sendto() failed \n");
    exit(-1);
  }

  // Wait to receive a message
  addr_len = sizeof(server_addr);
  retcode = recvfrom(client_s, in_buf, sizeof(in_buf), 0,
    (struct sockaddr *)&server_addr, &addr_len);
  if (retcode < 0)
  {
    printf("*** ERROR - recvfrom() failed \n");
    exit(-1);
  }

  // Output the received message
  printf("Received from server: %s \n", in_buf);

  // Close all open sockets
#ifdef WIN
  retcode = closesocket(client_s);
  if (retcode < 0)
  {
    printf("*** ERROR - closesocket() failed \n");
    exit(-1);
  }
#endif
#ifdef BSD
  retcode = close(client_s);
  if (retcode < 0)
  {
    printf("*** ERROR - close() failed \n");
    exit(-1);
  }
#endif

#ifdef WIN
  // This stuff cleans-up winsock
  WSACleanup();
#endif
}

这两个代码对我来说很好用,但是这是 2 个应用程序,我只想要一个可以充当服务器和客户端的应用程序。

所以我使用一个线程将这两个源代码合二为一。

同样,程序可以工作,但侦听器套接字接受来自广播消息的连接。

我想要的是监听器阻止来自环回地址的传入连接。

怎么做?

编辑:

示例我有 2 台计算机,一台是 A(192.168.1.100),另一台是 B(192.168.1.101),当我运行程序计算机 A 接收来自自身的消息时,我想要的是 A 只接收除A.

2014 年 1 月 27 日编辑:

经过几天的搜索,我想我无法找到解决问题的方法。
但是,还有另一种方法可以实现。

第一步是获取您的本地计算机 IP 地址。

第二步是在发送之前构建您的消息,例如格式为“ipAddress_messageToSend”。

第三步创建函数来处理来自 recvfrom() 函数的传入消息,该函数将传入消息按“_”分割
这样您将拥有二维数组,第一行是该消息来自的 IP 地址,第二行是消息本身。

第四步,你需要比较一下收到的邮件IP地址和你的电脑IP地址。
您可以使用下面的代码来获取 IP 地址。

char ac[80];
gethostname(ac, sizeof(ac));
struct hostent *phe = gethostbyname(ac);
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
printf("IP Address is : %s\n", inet_ntoa(addr));

第五步当比较IP并且它们相同时什么都不做,如果不是那么做你想做的事情。

希望对大家有所帮助

【问题讨论】:

  • 问题:你怎么知道你是从环回接收的?只是为了澄清一下:您想要的是服务器不接收来自自身的消息吗?
  • 对不起,我弄错了,它不是环回而是接收到自己广播的消息。是的,就是如何让服务器拒绝来自自己的消息
  • 如果您想要答案,请将该更正编辑到您的问题和标题中。目前两者都没有意义。
  • @rizkynggakool,我不同意对你的问题投反对票的观点。太极端了。这是一个有趣的问题,您正在研究的主题提出了分布式系统的许多问题。所以我赞成这个问题。请进行更正,以便其他人可以从问题和答案中受益。
  • @rodolk 谢谢,我想我有另一个解决方案可以解决我的问题,请查看编辑部分。我的英语不好,也许他们理解错了意思,这就是为什么我经常被人否决。

标签: c sockets network-programming chat winsock


【解决方案1】:

根据您对 cme​​ts 的响应,问题在于您的服务器正在接收来自在同一节点中运行的客户端的消息。您希望服务器过滤掉自己发出的那些消息。

为了实现服务器需要:

1-在开始之前,服务器会检测自己的接口和 IP 地址。 Winsock 应该有一个类似 getifaddrs 的函数。这里有一个与 Windows 相关的类似问题的链接:Get the IP Address of local computer 您将本地地址列表添加到列表或任何其他数据结构中。

这是 UNIX 的类似问题:Lazarus: How to list all the available network connection on a system?

2-每当收到消息,recvfrom后,服务器将client_addr.sin_addr.s_addr与自己的地址列表进行比较,以检测自己的消息。然后过滤掉那些消息。

我认为不可能以简单的方式以不同的方式从自身中过滤掉消息。在 Linux 中你可以使用 iptables 过滤掉自身的消息,我不知道 Windows 是否有类似的机制。

其他建议: 1-您应该为您的聊天应用程序使用多播而不是广播。这样,未运行聊天应用程序的系统就不会受到聊天消息的影响。

2-您可以使用确保每个对等方都可以读取所有消息的方法来补充多播或广播机制。广播和多播消息可能会被对等方丢失。有多种方法可以实现它。但是,一旦你解决了这个问题,那就是下一步。

【讨论】:

  • 哦,非常感谢,你真的很有帮助。这就是我真正想要的
【解决方案2】:

您正在从环回获取数据,因为您绑定到 INADDR_ANY。

有关更完整的解释/示例,请参阅此线程: Using a specific network interface for a socket in windows

【讨论】:

  • 是的,那么我应该使用什么值?对不起,我对你给我的链接感到困惑。
  • 我希望服务器接受除环回地址和程序本身的 ip 之外的所有内容
猜你喜欢
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-01
  • 1970-01-01
相关资源
最近更新 更多