我试图在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();
*/
答案 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);