写道
写道
网络编程
网络协议
协议分析
PCAP
linux下编译libpcap库时不支持rpcap。
RPCAP is a Remote Packet Capture system.
Windows PCAP
服务器编程
服务器编程中,不可避免的要使用到socket来实现客户端和服务器的连接通信,处理来自客户端的请求。这里不去详细将socket相关的东西,有关socket的东西可以参考另一篇文章:
写道
这里首先要考虑的是服务端怎么接收客户端的socket连接,客户端和服务器建立连接后,客户端向服务器发送请求,服务器怎么处理这些请求。在传统的socket编程模型中,我们通常在一个无限循环中,循环调用accept来接收客户端连接,在接收到一个客户端连接后,然后再来一个无限循环中,循环调用recv或者read来接收客户端的请求。
代码如下:
while (1)
{
fd_got = accept(fd, (struct sockaddr *) &sockaddr_got, &sockaddr_got_len);
while (1)
{
nbytes = recv(fd_got, buffer, size, 0);
... ...
}
}
在这段代码中,当有一个客户端连接建立后,代码进入内部的无限循环接收客户端的请求。当这样的话,就再也无法跳到外部循环中去接受其他客户端的连接请求。所以这段代码只能处理一个客户端的连接和请求,也就是第一个建立连接的客户端,后面的连接请求都无法accept,也就无法处理这些客户端的请求。
那么是否可以在recv返回后跳出到外部循环继续接收其他客户端的连接请求,这样其实也不行,因为这里recv调用是阻塞式的,想象一下这种情况,如果第一个客户端在建立连接后,一直都没有向服务器发送请求,这意味着这段代码会一直阻塞在recv调用上,无法继续执行下去,这样的话也无法跳出到外部循环。
当然我们也可以在recv的第4个参数flags上指定MSG_DONTWAIT,这样recv调用是非阻塞式的。这样的话,即便是第一个客户端一直都没有服务器发送请求,recv调用也不会阻塞。这样在recv调用后就可以跳出到外部循环继续接收其他客户端的连接请求。但是遗憾的是这里accept调用也是阻塞的,如果一直没有其他客户端请求连接,accept调用也会一直阻塞下去。这样也就无法接收已经建立连接的客户端的数据请求。
而且,如果这样的话,内部的那个循环其实就没什么用,代码如下:
while (1)
{
fd_got = accept(fd, (struct sockaddr *) &sockaddr_got, &sockaddr_got_len);
nbytes = recv(fd_got, buffer, size, 0);
... ...
}
这样的话,recv调用受accept的影响也无法循环接收来自客户端的请求。而且,就算accept返回后,后面的recv,也是接收的是最新连接的客户端的请求,无法处理之前建立连接的客户端请求。上面的代码,第一个客户端连接后,发送的请求还可以立即接收到,改成这样后,第一个客户端发送的请求又无法接收了。
上面的问题一个阻塞导致的问题,一个就是accept、recv调用都在同一线程下,导致他们相互影响。如果我们不考虑阻塞导致的问题,那么我们可以考虑让accept、recv调用在不同的线程或进程上,这样就不会相互影响,各自独立处理自己的接收客户端连接请求和自己的客户端请求。
比如主进程专门负责accept处理客户端连接,连接建立后,fork子进程去处理客户端请求。
while (1)
{
fd_got = accept(fd, (struct sockaddr *) &sockaddr_got, &sockaddr_got_len);
pid = fork();
if (pid == 0)
{
while (1)
{
nbytes = recv(fd_got, buffer, size, 0);
}
}
}
这段代码和上面的区别就调用了一下fork,改动很小,就能解决上面的问题。主进程不断循环处理客户端连接,一旦后连接,fork一个子进程去处理客户端请求。
当然,这里也可以使用线程,同样也可以解决上面的问题。
如果考虑通过非阻塞方式来解决上面的问题,
我们可以在创建socket后,将这个socket设置为非阻塞。这有两种方式实现,第一种就是在创建socket的时候,第2个参数指定SOCK_NONBLOCK,第二种方式就是通过fcntl设置O_NONBLOCK。这样,在这个socket下的相关网络调用,主要是些IO调用,都可以非阻塞式调用,不会阻塞。
还是上面的例子,设置为非阻塞后,accept、recv调用都不会阻塞。接着上面的逻辑继续,在recv返回后跳出到外部循环继续接收其他客户端的连接请求,由于accept、recv调用都不会阻塞,代码可以很顺利的执行下去,中间不会出现阻塞情况。
while (1)
{
fd_got = accept(fd, (struct sockaddr *) &sockaddr_got, &sockaddr_got_len);
if (fd_got != -1)
{
fd_set_add(fd_set, fd_got);
}
for (i = 0; i < nfds; i++)
{
nbytes = recv(fd_set[i], buffer, size, 0);
... ...
}
}
BIO
BIO即阻塞式IO
阻塞式(Blocking):
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
// posix thread
#include <pthread.h>
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
}
int start_routine_arg(void *arg)
{
return *((int*) arg);
}
void handle_accept(int fd)
{
handle_connect(fd);
handle_accept(fd);
}
void* accept_handler(void *arg)
{
pthread_t tid = pthread_self();
int fd = start_routine_arg(arg);
handle_accept(fd);
printf("tid %d\n", tid);
printf("fd %d\n", fd);
int *result = (int *) malloc(sizeof(int));
*result = 9;
return (void *) result;
}
// $ objdump -D -S server.exe > server.rasm
int main()
{
int fd;
struct sockaddr_in sock_addr;
pthread_t pt;
int result = 0;
int *presult = &result;
int **ppresult = &presult;
printf("%d\n", **ppresult);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
printf("socket error %d\n", errno);
return -1;
}
printf("fd %d\n", fd);
bzero(&sock_addr, sizeof(struct sockaddr_in));
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
sock_addr.sin_port = htons(2121);
if(bind(fd, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)) == -1)
{
printf("bind error %d\n", errno);
return -1;
}
if (listen(fd, 50) == -1)
{
printf("listen error %d\n", errno);
return -1;
}
if (pthread_create(&pt, NULL, accept_handler, (void *) &fd))
{
return -1;
}
if (pthread_join(pt, (void **) ppresult))
{
return -1;
}
printf("%d\n", **ppresult);
printf("...\n");
return 0;
}
NIO
NIO即非阻塞式IO
Socket NIO需要将socket设置为非阻塞式socket。
非阻塞式(Non-Blocking):
可以通过fcntl函数设置O_NONBLOCK使socket工作在非阻塞式(Non-Blocking)模式下。
从Linux 2.6.27后,还可以在创建socket的时候设置SOCK_NONBLOCK使socket工作在非阻塞式(Non-Blocking)模式下,这种方式是Linux-specific的。
以下非阻塞式(Non-Blocking)例子是在创建socket的时候设置SOCK_NONBLOCK使socket工作在非阻塞式(Non-Blocking)模式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
// posix thread
#include <pthread.h>
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT 1236
typedef struct Args
{
char *host;
int port;
int backlog;
} Args_t;
Args_t* parseArgs(int argc, char** argv, Args_t* args)
{
// mask param host setting(0x01), and param port setting(0x02)
unsigned short mask = 0;
if (argc > 1)
{
char** p_argv = argv;
int i;
for (i = 1; i < argc; i++)
{
char *s_param = *(p_argv + i);
if (! strcmp("-h", s_param) || ! strcmp("--help", s_param) || ! strcmp("/?", s_param))
{
__USAGES:
printf("%s\n", *argv);
printf("options:\n");
printf("\t-h --help /?\n");
printf("\t usage.\n");
printf("\t-H --host[=localhost]\n");
printf("\t the host to bind, default to localhost. well-form with formats: \n");
printf("\t 1) -Hhost, for example: -Hlocalhost\n");
printf("\t 2) --host=host, for example: --host=localhost\n");
printf("\t 3) --host host, for example: --host localhost\n");
printf("\t if any, for example -Hany Or --host=any Or --host any, this represents INADDR_ANY while binding.\n");
printf("\t--bind-any\n");
printf("\t represents INADDR_ANY while binding. this same as -Hany Or --host=any Or --host any\n");
printf("\t-p --port[=1236]\n");
printf("\t the port to listen, default to 1236. well-form with formats: \n");
printf("\t 1) -pport, for example: -p1236\n");
printf("\t 2) --port=port, for example: --port=1236\n");
printf("\t 3) --port port, for example: --port 1236\n");
printf("\t--backlog[=50]\n");
printf("\t represents the maximum length to which the queue of pending connections.\n");
return NULL;
}
else if (! strncmp("-H", s_param, 2))
{
char *host;
if (mask & 0x01)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (strlen(s_param) == 2)
{
printf("invalid param: %s.\n", s_param);
goto __USAGES;
}
host = s_param + 2;
args->host = host;
mask |= 0x01;
}
else if (! strncmp("--host", s_param, 6))
{
if (mask & 0x01)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--host", s_param))
{
if (i + 1 < argc)
{
args->host = *(p_argv + (++i));
}
else
{
printf("invalid param: %s, well-form with formats: --host=host Or --host host\n", s_param);
goto __USAGES;
}
}
else if(! strncmp("--host=", s_param, 7))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
args->host = token;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
mask |= 0x01;
}
else if (! strcmp("--bind-any", s_param))
{
args->host = "any";
}
else if (! strncmp("-p", s_param, 2))
{
int port;
if (mask & 0x02)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (strlen(s_param) == 2)
{
printf("invalid param: %s.\n", s_param);
goto __USAGES;
}
port = atoi(s_param + 2);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
mask |= 0x02;
}
else if (! strncmp("--port", s_param, 6))
{
if (mask & 0x02)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--port", s_param))
{
if (i + 1 < argc)
{
s_param = *(p_argv + (++i));
int port = atoi(s_param);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s, well-form with formats: --port=port Or --port port\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--port=", s_param, 7))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
int port = atoi(token);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
mask |= 0x02;
}
else if (! strncmp("--backlog", s_param, 9))
{
if (mask & 0x04)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--backlog", s_param))
{
if (i + 1 < argc)
{
s_param = *(p_argv + (++i));
int backlog = atoi(s_param);
if (backlog != 0)
{
args->backlog = backlog;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s, well-form with formats: --backlog=backlog Or --backlog backlog\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--backlog=", s_param, 10))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
int backlog = atoi(token);
if (backlog != 0)
{
args->backlog = backlog;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
mask |= 0x04;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
}
return args;
}
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
// ignore, in a non-blocking
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
}
int start_routine_arg(void *arg)
{
return *((int*) arg);
}
void handle_accept(int fd)
{
handle_connect(fd);
//handle_accept(fd);
}
void* accept_handler(void *arg)
{
pthread_t tid = pthread_self();
int fd = start_routine_arg(arg);
printf("tid %d\n", tid);
printf("fd %d\n", fd);
while (1)
{
handle_accept(fd);
}
int *result = (int *) malloc(sizeof(int));
*result = 9;
return (void *) result;
}
// $ objdump -D -S server.exe > server.rasm
void main(int argc, char** argv)
{
int fd;
struct sockaddr_in sock_addr; // #include <netinet/in.h>
Args_t args = {DEFAULT_HOST, DEFAULT_PORT, 50};
pthread_t pt;
int result = 0;
int *presult = &result;
int **ppresult = &presult;
printf("%d\n", **ppresult);
if (parseArgs(argc, argv, &args) == NULL)
{
return;
}
printf("listening on %s:%d, backlog: %d\n", strcmp("any", args.host) == 0 ? "" : args.host, args.port, args.backlog);
#ifndef SOCK_NONBLOCK
#error "SOCK_NONBLOCK not support."
#endif
fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (fd == -1)
{
printf("socket error %d\n", errno);
return;
}
printf("fd %d\n", fd);
bzero(&sock_addr, sizeof(struct sockaddr_in)); // #include <string.h>
sock_addr.sin_family = AF_INET;
if (! strcmp("any", args.host))
{
printf("bind any\n");
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
}
else if (! strcmp("localhost", args.host))
{
in_addr_t sin_addr = inet_addr("127.0.0.1");
if (sin_addr == INADDR_NONE)
{
fprintf(stderr, "invalid address %s\n", args.host);
return;
}
sock_addr.sin_addr.s_addr = sin_addr;
}
else
{
if (! inet_aton(args.host, &(sock_addr.sin_addr)))
{
fprintf(stderr, "invalid address %s\n", args.host);
return;
}
}
sock_addr.sin_port = htons(args.port);
if(bind(fd, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)) == -1)
{
printf("bind error %d\n", errno);
return;
}
if (listen(fd, args.backlog) == -1)
{
printf("listen error %d\n", errno);
return;
}
if (pthread_create(&pt, NULL, accept_handler, (void *) &fd))
{
printf("pthread create error %d\n", errno);
return;
}
if (pthread_join(pt, (void **) ppresult))
{
printf("pthread join error %d\n", errno);
return;
}
printf("%d\n", **ppresult);
}
以下非阻塞式(Non-Blocking)例子是通过fcntl函数设置O_NONBLOCK使socket工作在非阻塞式(Non-Blocking)模式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
// posix thread
#include <pthread.h>
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT 1236
typedef struct Args
{
char *host;
int port;
int backlog;
} Args_t;
Args_t* parseArgs(int argc, char** argv, Args_t* args)
{
if (argc > 1)
{
char** p_argv = argv;
int port_set_flag = 0, allow_port_0 = 0;
int i;
for (i = 1; i < argc; i++)
{
char *s_param = *(p_argv + i);
if (! strcmp("-h", s_param) || ! strcmp("--help", s_param) || ! strcmp("/?", s_param))
{
__USAGES:
printf("%s\n", *argv);
printf("options:\n");
printf("\t-h --help /?\n");
printf("\t usage.\n");
printf("\t-H --host[=localhost]\n");
printf("\t the host to bind, default to localhost. well-form with formats: \n");
printf("\t 1) -Hhost, for example: -Hlocalhost\n");
printf("\t 2) --host=host, for example: --host=localhost\n");
printf("\t 3) --host host, for example: --host localhost\n");
printf("\t if any, for example -Hany Or --host=any Or --host any, this represents INADDR_ANY while binding.\n");
printf("\t--bind-any\n");
printf("\t represents INADDR_ANY while binding. this same as -Hany Or --host=any Or --host any\n");
printf("\t-p --port[=1236]\n");
printf("\t the port to listen, default to 1236. well-form with formats: \n");
printf("\t 1) -pport, for example: -p1236\n");
printf("\t 2) --port=port, for example: --port=1236\n");
printf("\t 3) --port port, for example: --port 1236\n");
printf("\t the port set to 0 is not a satisfied value, a random port would be assigned. by default the port set to 0 is not allowed\n");
printf("\t--allow-port-zero\n");
printf("\t default, the port set to 0 is not allowed, param --allow-port-zero allow the port set to 0\n");
printf("\t--backlog[=50]\n");
printf("\t represents the maximum length to which the queue of pending connections.\n");
return NULL;
}
else if (! strncmp("-H", s_param, 2))
{
char *host;
if (args->host != NULL)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (strlen(s_param) == 2)
{
printf("invalid param: %s.\n", s_param);
goto __USAGES;
}
host = s_param + 2;
args->host = host;
}
else if (! strncmp("--host", s_param, 6))
{
if (args->host != NULL)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--host", s_param))
{
if (i + 1 < argc)
{
args->host = *(p_argv + (++i));
}
else
{
printf("invalid param: %s, well-form with formats: --host=host Or --host host\n", s_param);
goto __USAGES;
}
}
else if(! strncmp("--host=", s_param, 7))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
args->host = token;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else if (! strcmp("--bind-any", s_param))
{
if (args->host != NULL)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
args->host = "any";
}
else if (! strncmp("-p", s_param, 2))
{
int port;
if (args->port > 0)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (strlen(s_param) == 2)
{
printf("invalid param: %s.\n", s_param);
goto __USAGES;
}
port = atoi(s_param + 2);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--port", s_param, 6))
{
if (args->port > 0)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--port", s_param))
{
if (i + 1 < argc)
{
s_param = *(p_argv + (++i));
int port = atoi(s_param);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s, well-form with formats: --port=port Or --port port\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--port=", s_param, 7))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
int port = atoi(token);
if (port != 0)
{
args->port = port;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else if (! strcmp("--allow-port-zero", s_param))
{
allow_port_0 = 1;
}
else if (! strncmp("--backlog", s_param, 9))
{
if (args->backlog > 0)
{
printf("invalid param: %s, dump.\n", s_param);
goto __USAGES;
}
if (! strcmp("--backlog", s_param))
{
if (i + 1 < argc)
{
s_param = *(p_argv + (++i));
int backlog = atoi(s_param);
if (backlog != 0)
{
args->backlog = backlog;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s, well-form with formats: --backlog=backlog Or --backlog backlog\n", s_param);
goto __USAGES;
}
}
else if (! strncmp("--backlog=", s_param, 10))
{
char *token = strtok(s_param, "=");
if (token != NULL)
{
token = strtok(NULL, "=");
if (token != NULL)
{
int backlog = atoi(token);
if (backlog != 0)
{
args->backlog = backlog;
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
else
{
printf("invalid param: %s\n", s_param);
goto __USAGES;
}
}
if (! allow_port_0 && args->port == 0)
{
fprintf(stderr, "port set to 0 is not allowed\n");
goto __USAGES;
}
}
return args;
}
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
// ignore, in a non-blocking
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
}
int start_routine_arg(void *arg)
{
return *((int*) arg);
}
void handle_accept(int fd)
{
handle_connect(fd);
//handle_accept(fd);
}
void* accept_handler(void *arg)
{
pthread_t tid = pthread_self();
int fd = start_routine_arg(arg);
printf("tid %d\n", tid);
printf("fd %d\n", fd);
while (1)
{
handle_accept(fd);
}
int *result = (int *) malloc(sizeof(int));
*result = 9;
return (void *) result;
}
// $ objdump -D -S server.exe > server.rasm
void main(int argc, char** argv)
{
int fd, fd_flags;
struct sockaddr_in sock_addr; // #include <netinet/in.h>
Args_t args;
memset(&args, 0, sizeof(Args_t));
pthread_t pt;
int result = 0;
int *presult = &result;
int **ppresult = &presult;
printf("%d\n", **ppresult);
if (parseArgs(argc, argv, &args) == NULL)
{
return;
}
if (args.host == NULL)
{
args.host = DEFAULT_HOST;
}
if (args.port == 0)
{
args.port = DEFAULT_PORT;
}
if (args.backlog == 0)
{
args.backlog = 50;
}
printf("listening on %s:%d, backlog: %d\n", strcmp("any", args.host) == 0 ? "" : args.host, args.port, args.backlog);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
printf("socket error %d\n", errno);
return;
}
printf("fd %d\n", fd);
fd_flags = fcntl(fd, F_GETFL);
if (fd_flags == -1)
{
fprintf(stderr, "fcntl error %d\n", errno);
return;
}
fd_flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, fd_flags) == -1)
{
fprintf(stderr, "fcntl error %d\n", errno);
return;
}
bzero(&sock_addr, sizeof(struct sockaddr_in)); // #include <string.h>
sock_addr.sin_family = AF_INET;
if (! strcmp("any", args.host))
{
printf("bind any\n");
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
}
else if (! strcmp("localhost", args.host))
{
in_addr_t sin_addr = inet_addr("127.0.0.1");
if (sin_addr == INADDR_NONE)
{
fprintf(stderr, "invalid address %s\n", args.host);
return;
}
sock_addr.sin_addr.s_addr = sin_addr;
}
else
{
if (! inet_aton(args.host, &(sock_addr.sin_addr)))
{
fprintf(stderr, "invalid address %s\n", args.host);
return;
}
}
sock_addr.sin_port = htons(args.port);
if(bind(fd, (struct sockaddr *) &sock_addr, sizeof(struct sockaddr)) == -1)
{
printf("bind error %d\n", errno);
return;
}
if (listen(fd, args.backlog) == -1)
{
printf("listen error %d\n", errno);
return;
}
if (pthread_create(&pt, NULL, accept_handler, (void *) &fd))
{
printf("pthread create error %d\n", errno);
return;
}
if (pthread_join(pt, (void **) ppresult))
{
printf("pthread join error %d\n", errno);
return;
}
printf("%d\n", **ppresult);
}
AIO
AIO即异步IO
在调用accept系统调用函数时,出现14号errno错误,查看定义如下:
#defineEFAULT 14/* Bad address */
在https://linux.die.net/man/2/accept4上对该错误描述如下:
EFAULT The addr argument is not in a writable part of the user address space.
这个错误很少遇到,无意中把代码写成:
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
// ignore, in a non-blocking
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
}
void handle_accept(int fd)
{
handle_connect(fd);
handle_accept(fd);
}
handle_accept内部递归调用,导致出现上面那个错误。
将accept这段代码注释掉后,
int handle_connect(int fd)
{
struct sockaddr sock_addr;
int addrlen = sizeof(struct sockaddr);
/*
int a_fd = accept(fd, &sock_addr, &addrlen);
if (a_fd == -1)
{
if (errno == EWOULDBLOCK)
{
// ignore, in a non-blocking
}
else
{
printf("accept error %d\n", errno);
}
return -1;
}
else
{
printf("accept new connection from %d\n", a_fd);
return a_fd;
}
*/
}
程序启动后进程就直接退出,没报任何错误,唯一确定是已经出错的原因是因为产生了.stackdump文件,但该文件是空的。也无法根据.stackdump文件去定位原因。
相关推荐
这组资源,"Linux下C语言应用编程(作者-杨铸)配套教学ppt",提供了对Linux环境下C语言编程的深入理解和实践指导。以下是一些核心知识点的详细说明: 1. **Linux下C语言编程环境**: - `11-Linux下C语言编程环境....
C语言编程基础知识 在 Linux 操作系统中,C 语言编程是非常重要的编程技术。要进行 C 语言编程,需要了解一些基础知识,包括源程序编译、Makefile 的编写、程序库的链接、程序的调试、头文件和系统求助等。 1. 源...
源代码文件“linuxc.tgz”是一个压缩包,其中包含了书中各个主题的实例代码。学生可以参考这些代码来加深理解,同时通过实际操作来锻炼编程技能。源代码涵盖了上述所有PPT讲解的主题,如简单的文件操作示例、多进程...
linux下的c语言-网络-网络编程面试题.pdf 在这份面试题中,我们将讨论 Linux 下 C 语言的网络编程相关问题,涵盖了基础部分和网络/网络编程部分。 基础部分: 1. 在 32 位 Linux 或 Unix 中,以下程序的结果是...
Linux下的C语言编程是开发人员在开源环境中进行系统级编程和应用开发的重要工具。C语言是一种强大的、低级别的编程语言,特别适合于操作系统和设备驱动的开发,而在Linux这一类Unix-like系统中,C语言更是得到了广泛...
linux C语言 网络编程教程及源码 一、网络应用层编程 1、Linux网络编程01——网络协议入门 2、Linux网络编程02——无连接和面向连接的区别 3、Linux网络编程03——字节序和地址转换 4、Linux网络编程04——套接字 5...
### Linux C语言编程一站式学习知识点概览 #### 标题:Linux C语言编程一站式学习--pdf完整版 - **核心内容**:本书旨在为初学者和有一定基础的学习者提供一个全面且系统的C语言编程学习资源,特别强调在Linux环境...
Linux下的C语言编程基础知识篇 本文将详细介绍在Linux下进行C语言编程所需要的基础知识,包括源程序编译、Makefile的编写、程序库的链接、程序的调试、头文件和系统求助等内容。 一、源程序的编译 在Linux下,...
用下列命令编译程序: gcc -Wall telnet-server -o telnetd 启动telnet服务: ./telnetd --daemon #以root用户身份在23端口(即telnet默认端口服务) 或 ./telnetd -P 7838 #以非root用户身份
Linux 下 C 语言编程入门是一门重要的编程技术,涵盖了 Linux 程序设计的基础知识,包括进程介绍、文件操作、时间概念、信号处理、消息管理、线程操作和网络编程等方面的知识点。 知识点 1: Linux 程序设计入门 -- ...
### Linux下C语言编程入门知识点概述 #### 一、标题与描述解读 - **标题**:“Linux下C语言编程入门.pdf”明确指出本书是关于在Linux环境下进行C语言编程的入门指南。 - **描述**:“带领你从Windows走向Linux”,...
在上述的压缩包文件中,包含了“Linux下C语言编程--文件操作.rtf”和“www.pudn.com.txt”。这些文档可能提供了更详细的代码示例和解释,建议解压后阅读以加深理解和实践。 总之,无论是C语言还是C++,在Linux环境...
Linux多线程服务端编程:使用muduo+C网络库.pdf Linux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:...
在Linux环境下进行C语言编程是许多开发者和技术爱好者深入操作系统内核、实现系统级程序或高效应用的重要途径。本文将详细探讨“Linux下C语言”这一主题,基于标题和描述提供的信息,我们将涵盖C语言的基本概念、...
3. C语言编程 文档提到基于C语言进行网络编程。C语言由于其高效和接近硬件的特性,成为编写网络程序的首选语言。它为网络编程提供了丰富的库函数,例如标准I/O库、网络库等。 4. 套接字编程 套接字是网络通信的基本...
在Linux环境下进行C语言应用编程是一项基础且重要的技能,它涉及到操作系统、程序设计与系统接口等多个领域的知识。这本书的随书源代码提供了丰富的实例,帮助读者深入理解和实践C语言在Linux下的应用。以下是对这些...
### C语言Linux系统编程入门知识点概述 #### 一、Linux下的C语言编程基础 ##### 1. 源程序的编译 - **GCC编译器**: 在Linux环境下,使用GCC(GNU Compiler Collection)作为主要的编译工具。GCC不仅支持C语言,还...
其次,书中的内容可能涉及C语言编程,因为C语言是Linux编程的主要语言。读者将学习如何使用标准C库,以及如何编写与系统接口交互的代码,如系统调用。此外,书中的章节可能还会讲解C++编程,特别是在Linux环境下的...
Linux 下的 C 语言网络编程面试题 本篇文章针对 Linux 下的 C 语言网络编程面试题进行了详细的解释和分析,涵盖了基础部分和网络/网络编程部分。 基础部分: 1. 程序结果分析:在 32 位 Linux 或 Unix 中,程序的...
### Linux操作系统下C语言编程入门知识点详解 #### 一、目录介绍 本文档旨在为初次接触Linux环境下C语言编程的学习者提供全面的指导。主要内容包括Linux下的C语言基础知识、进程管理、文件操作、时间处理、信号...