socket api不在类中工作

时间:2012-02-24 23:46:59

标签: c++ c sockets

我试图在C ++类中包装unix socket api调用,以便更容易使用。我已经用C语言编写了一个最小的工作示例,并在一个类中复制了代码。从下面可以看出,无论是调用包装代码的函数版本还是方法版本,代码都是相同的。请参阅下面的丑陋临时代码:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

static int sockfd;
static int rec_sock;
static int len;

typedef struct sockaddr_in sockaddr_in;
static sockaddr_in addr;
static sockaddr_in recaddr;

int ServerSocket_socket(int family, int type, int protocol)
{
    sockfd = socket(AF_INET, SOCK_STREAM, 0)
    return sockfd;
}

void ServerSocket_bind(int port)
{
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_family = AF_INET;
    addr.sin_port = port;

    bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
}

void ServerSocket_printInfo(void)
{
    len = sizeof(addr);
    getsockname(sockfd, (struct sockaddr *)&addr, (socklen_t *)&len);
    printf("ip = %s, port = %d\n", inet_ntoa(addr.sin_addr), (addr.sin_port));
}

void ServerSocket_listen(int backlog)
{
    listen(sockfd, backlog);
}

void ServerSocket_accept(void)
{
  rec_sock = accept(sockfd, (struct sockaddr *)(&recaddr), (socklen_t *)&len);
}

void ServerSocket_printPeerInfo(void)
{
    printf("remote machine = %s, port = %x, %x.\n", inet_ntoa(recaddr.sin_addr), recaddr.sin_port, ntohs(recaddr.sin_port));
    memset(&recaddr, 0, sizeof(recaddr));
    len = sizeof(addr);
    getpeername(rec_sock, (struct sockaddr *)&recaddr, (socklen_t *) &len);
}

void ServerSocket_write(void)
{
  write(rec_sock, "hi, there", 10);
  sleep(20);
  exit(1);
}

struct ServerSocket
{
  int socket(int family, int type, int protocol)
  {
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      return sockfd;  
  }

  void bind(int port)
  {
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_family = AF_INET;
    addr.sin_port = port;

    ::bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
  }

  void printInfo(void)
  {
      len = sizeof(addr);
      getsockname(sockfd, (struct sockaddr *)&addr, (socklen_t *)&len);
      printf("ip = %s, port = %d\n", inet_ntoa(addr.sin_addr), (addr.sin_port));
  }

  void listen(int backlog)
  {
      ::listen(sockfd, backlog);
  }

  void accept(void)
  {
    rec_sock = ::accept(sockfd, (struct sockaddr *)(&recaddr), (socklen_t *)&len);
  }

  void printPeerInfo(void)
  {
      printf("remote machine = %s, port = %x, %x.\n", inet_ntoa(recaddr.sin_addr), recaddr.sin_port, ntohs(recaddr.sin_port));
      memset(&recaddr, 0, sizeof(recaddr));
      len = sizeof(addr);
      getpeername(rec_sock, (struct sockaddr *)&recaddr, (socklen_t *) &len);
      printf("remote machine = %s, port = %d, %d.\n", inet_ntoa(recaddr.sin_addr), recaddr.sin_port, ntohs(recaddr.sin_port));
  }

  void write(void)
  {
    ::write(rec_sock, "hi, there", 10);
    sleep(20);
    exit(1);
  }
};

当我调用这些函数时,代码就像一个冠军。但是,当我运行几乎完全相同的代码包装方法时,我得到一个拒绝连接。知道这个最小的代码更改正在做什么导致示例不起作用吗?

   ServerSocket_socket(AF_INET, SOCK_STREAM, 0);
    ServerSocket_bind(1031);
    ServerSocket_printInfo();
    ServerSocket_listen(5);
    ServerSocket_accept();
    ServerSocket_printPeerInfo();
    ServerSocket_write();
  /*
    ServerSocket sock;
    sock.socket(AF_INET, SOCK_STREAM, 0);
    sock.bind(1031);
    sock.printInfo();
    sock.listen(5);
    sock.accept();
    sock.printPeerInfo();
    sock.write();
  */

2 个答案:

答案 0 :(得分:2)

在ServerSocket_bind中更改:

addr.sin_port = port;

addr.sin_port = htons(port);

它应该有效。另外,使用strace调试系统调用(或libc的ltrace),如:

strace -f ./a.out

ltrace ./a.out

答案 1 :(得分:2)

试试这个:

#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 

typedef struct sockaddr_in sockaddr_in; 

struct ServerSocket 
{ 
  int sockfd; 
  int rec_sock; 

  ServerSocket()
  {
    sockfd = -1; 
    rec_sock = -1; 
  }

  ~ServerSocket()
  {
    if (rec_sock != -1) closesocket(rec_sock); 
    if (sockfd != -1) closesocket(sockfd); 
  }

  void socket(int family, int type, int protocol) 
  { 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
  } 

  void bind(int port) 
  { 
    sockaddr_in addr; 
    memset(&addr, 0, sizeof(addr)); 
    addr.sin_addr.s_addr = INADDR_ANY; 
    addr.sin_family = AF_INET; 
    addr.sin_port = htons(port); 

    ::bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); 
  } 

  void printInfo(void) 
  { 
    sockaddr_in addr; 
    memset(&addr, 0, sizeof(addr)); 
    int len = sizeof(addr); 
    getsockname(sockfd, (struct sockaddr *)&addr, (socklen_t *)&len); 
    printf("ip = %s, port = %d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  } 

  void listen(int backlog) 
  { 
    ::listen(sockfd, backlog); 
  } 

  void accept(void) 
  { 
    rec_sock = ::accept(sockfd, (struct sockaddr *)(&recaddr), (socklen_t *)&len); 
  } 

  void printPeerInfo(void) 
  { 
    sockaddr_in recaddr; 
    memset(&recaddr, 0, sizeof(recaddr)); 
    int len = sizeof(addr); 
    getpeername(rec_sock, (struct sockaddr *)&recaddr, (socklen_t *) &len); 
    printf("remote machine = %s, port = %d.\n", inet_ntoa(recaddr.sin_addr), ntohs(recaddr.sin_port)); 
  } 

  void write(void *data, int len) 
  { 
    ::write(rec_sock, (char*)data, len); 
  } 
}; 

ServerSocket sock;  
sock.socket(AF_INET, SOCK_STREAM, 0);  
sock.bind(1031);  
sock.printInfo();  
sock.listen(5);  
sock.accept();  
sock.printPeerInfo();  
sock.write("hi, there", 10);  
sleep(20);   
exit(1);