【问题标题】:Beginner's Socket Programming in C初学者的 C 套接字编程
【发布时间】:2011-04-26 14:29:58
【问题描述】:

我刚开始学习套接字编程,发现它很有趣。 目前我正在同一台计算机上制作服务器和客户端,因此我可以将ip地址作为环回地址,127.0.0.1一切似乎都很好!

但现在我正在考虑拥有两台计算机并做这件事.. 我有以下问题

  1. 假设一台计算机是服务器,另一台是客户端。现在,服务器代码是否应该驻留在服务器计算机上,客户端代码应该驻留在客户端上??李>
  2. 服务器代码中,当我们为bind()提供ip地址时,应该是系统的ip地址我们可以通过ipconfig 找到还是应该仍然是环回地址?
  3. 在客户端代码中,我猜目的地的IP地址应该是服务器计算机的IP地址吧??
  4. 最后也是最重要的事情,如何连接两台计算机??

我附上了我开始使用的简单服务器和客户端消息传递代码。请指导我完成我需要进行的更改..

服务器代码

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

#define MYPORT 3500

int main()
{
    int sockfd;
    int clientfd;
    int bytes_read;
    char buf[100];
    int struct_size;
    struct sockaddr_in my_addr;
    struct sockaddr_in con_addr;
    
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(MYPORT);
    my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    my_addr.sin_zero[8]='\0';

    bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr));

    listen(sockfd,5);
    
    struct_size = sizeof(con_addr);
    clientfd = accept(sockfd, (struct sockaddr*)&con_addr, &struct_size);

    bytes_read = read(clientfd, buf, 100);
    buf[bytes_read] = '\0';
    printf("Message from client:%d is %s \n",clientfd, buf);

    close(sockfd);
    close(clientfd);
}

客户代码

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<string.h>
#include<stdio.h>

#define DESTPORT 3500

int main()
{

    struct sockaddr_in dest_addr;
    
    int sockfd = socket(AF_INET,SOCK_STREAM,0);

    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(DESTPORT);
    dest_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    dest_addr.sin_zero[8]='\0';

    connect(sockfd,(struct sockaddr*)&dest_addr, sizeof(struct sockaddr));

    char msg[100];
    printf("Enter you message: ");
    gets(&msg); 
    
    int w = write(sockfd, msg, strlen(msg));
    
    close(sockfd);
    printf("Client Dying.....\n"); 

    return 0;
}

【问题讨论】:

    标签: c sockets client


    【解决方案1】:

    1) 正确。

    2) 在服务器端,您可以绑定到 0.0.0.0,这意味着“所有 (IPv4) 接口”。

    3) 是的,你是对的。

    4) 最常见的是通过以太网交换机(或交叉以太网电缆,但很难找到)。

    【讨论】:

      【解决方案2】:

      服务器应该bind0.0.0.0(任意),除非您试图限制访问(在这种情况下,您应该真正使用防火墙而不是端口绑定)。正确的做法其实是:

      struct addrinfo *ai, hints = { .ai_flags = AI_PASSIVE };
      if (getaddrinfo(0, "1234", &hints, &ai)) goto error;
      int fd = socket(ai->ai_family, SOCK_STREAM, 0);
      bind(fd, ai->ai_addr, ai->ai_addrlen);
      

      当然,添加一些错误检查。将“1234”替换为您的端口号。

      【讨论】:

      • 按照我想要的方式解决了我的问题。非常感谢 :-) 你能推荐一些好的资源来阅读现代套接字编程吗??
      • 基本上是 getaddrinfogetnameinfosocketbindconnectlisten、@987654331 的手册页(或 POSIX 文档,此处为:pubs.opengroup.org/onlinepubs/9699919799/functions/…) @、sendtorecvfromselect 几乎就是您所需要的。您在较早的示例和教程中看到的所有复杂性都只是遗留的包袱,不利于 IPv6 支持和可移植性。
      • 为什么不在任何地方指定端口?
      • 愚蠢的错误。修复。当然你可以让bind给你分配一个端口号,然后用getsocknamegetnameinfo记录下来发布给客户使用。
      • 当您使用getaddrinfo() 时,您应该始终循环遍历所有结果并为每个侦听地址创建一个套接字。如果您只想简单地使用 IPv4 any 地址,那么首先没有理由使用getaddrinfo()。根据系统配置,您的代码可能会导致令人惊讶的情况。
      【解决方案3】:

      127.0.0.1 是 localhost 你当前所在机器的环回地址。 如果您使用两个单独的框,您可能希望将其更改为客户端中的真实 IP。

      是的,客户端通常(但不总是)在服务器的另一个物理盒子上。 如果你愿意,你可以在 omne box 上运行这两个部分

      【讨论】:

      • 谢谢大佬。。所以,我把客户端代码里的ip地址改成服务器机器的ip地址。。很好。。但是服务器代码上的ip地址怎么办,这里,my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
      • 您永远不必手动戳sin_addr.s_addr 等。这是 90 年代初期的一种糟糕的套接字编程,会给您带来很多麻烦,并且难以支持 IPv6。请参阅我的答案,了解绑定套接字以进行侦听的现代方式。
      【解决方案4】:

      1) 假设一台计算机是服务器,另一台是客户端。现在,服务器代码是否应该驻留在服务器计算机上,而客户端代码应该驻留在客户端计算机上?

      我不认为我从正确的角度理解这一点...大声笑。如果您的客户端代码在服务器端,您如何分配任何内存块或调用客户端计算机上的东西?

      2) 在服务器代码中,当我们为bind()提供IP地址时,应该是我们可以通过ipconfig找到的系统IP地址,还是应该仍然是环回地址??

      我们在手册页上的内容:

       int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
      

      "bind() 将 addr 指定的地址分配给文件描述符 sockfd 引用的套接字。addrlen 指定 addr 指向的地址结构的大小,以字节为单位。传统上,此操作称为“分配一个套接字的名称”。 在 SOCK_STREAM 套接字可以接收连接之前,通常需要使用 bind() 分配一个本地地址(请参阅 accept(2))。"

      在你的情况下,我想,127.0.0.1 是你要找的。简而言之,你所说的地址更有可能是你设置到 server_addr 结构的那个。

      3)在客户端代码中,我猜目的地的IP地址应该是服务器计算机的IP地址吧??

      是的。

      4) 最后也是最重要的事情,我如何连接两台计算机??

      听起来像是经典的聊天室应用程序。 据我所知(我是一个新手......),UDP(用户数据报协议)编程和 API 值得一试,可能。如果你想坚持 TCP/IP,两台任意计算机基本上不会连接到每个其他但两者都与服务器保持联系,服务器将成为它们之间的基石。

      更重要的是,我查看了一些套接字手册页:

       int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
      

      "connect()系统调用将文件描述符sockfd引用的socket连接到addr指定的地址。addrlen参数指定addr的大小。addr中地址的格式由地址空间决定套接字 sockfd;有关更多详细信息,请参见 socket(2)。"

      我认为这从理论上完美地解释了您的问题。

      【讨论】:

      • 我是套接字编程的新手,这个概念是否正确,前提是我们可以通过 LAN 或 WAN 将服务器和客户端计算机连接在一起,然后服务器和客户端驻留在两台不同的计算机中,并且服务器还可以在服务器端计算机上为客户端分配一些内存。我认为它在概念上是正确的,如果我错了,请纠正我
      猜你喜欢
      • 1970-01-01
      • 2023-03-27
      • 2014-11-22
      • 2012-05-29
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多