【发布时间】:2014-03-01 02:26:35
【问题描述】:
我有这个发送和接收 lambda 函数的简单客户端/服务器套接字代码。问题出在 recvlambda() 函数内部的客户端上,当我在收到它后尝试调用 lambda 时,我得到 seg fault @
printf("Hello World! %i, %i\n", x, y);
调试发现 x 和 y 无法访问,它们的内存地址是错误的。
我在 Ubuntu 13.10 上使用 gcc 4.8.1。
我通过将 x、y 复制到 sendlambda() 函数中的 lambda 来传递。这不应该是段错误。知道为什么吗?
#include <iostream>
#include <time.h>
#include <gmpxx.h>
using namespace std;
typedef int (*func)();
/* Server code in C */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <functional>
void sendlambda(int ConnectFD)
{
int x = 2342342;
int y = 23454234;
function<int (void)> f = [x, y]() mutable -> int
{
printf("Hello World! %i, %i\n", x, y);
};
printf("sending lambda of %i bytes\n", sizeof(f));
write(ConnectFD, (void*)&f, sizeof(f));
}
void recvlambda(int SocketFD)
{
char buffer[1024];
read(SocketFD, (void*)buffer, sizeof(buffer));
function<int (void)> &f = *(function<int (void)> *)buffer;
f();
}
int server()
{
printf("server\n");
struct sockaddr_in stSockAddr;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == SocketFD)
{
printf("can not create socket\n");
exit(EXIT_FAILURE);
}
memset(&stSockAddr, 0, sizeof(stSockAddr));
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(1100);
stSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(-1 == bind(SocketFD,(struct sockaddr *)&stSockAddr, sizeof(stSockAddr)))
{
printf("error bind failed\n");
close(SocketFD);
exit(EXIT_FAILURE);
}
if(-1 == listen(SocketFD, 10))
{
printf("error listen failed\n");
close(SocketFD);
exit(EXIT_FAILURE);
}
for(;;)
{
int ConnectFD = accept(SocketFD, NULL, NULL);
if(0 > ConnectFD)
{
printf("error accept failed\n");
close(SocketFD);
exit(EXIT_FAILURE);
}
/* perform read write operations ...*/
sendlambda(ConnectFD);
if (-1 == shutdown(ConnectFD, SHUT_RDWR))
{
printf("can not shutdown socket\n");
close(ConnectFD);
close(SocketFD);
exit(EXIT_FAILURE);
}
close(ConnectFD);
}
close(SocketFD);
return EXIT_SUCCESS;
}
int client()
{
printf("client\n");
struct sockaddr_in stSockAddr;
int Res;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (-1 == SocketFD)
{
printf("cannot create socket\n");
exit(EXIT_FAILURE);
}
memset(&stSockAddr, 0, sizeof(stSockAddr));
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(1100);
Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
if (0 > Res)
{
printf("error: first parameter is not a valid address family\n");
close(SocketFD);
exit(EXIT_FAILURE);
}
else if (0 == Res)
{
printf("char string (second parameter does not contain valid ipaddress\n)");
close(SocketFD);
exit(EXIT_FAILURE);
}
if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr)))
{
printf("connect failed\n");
close(SocketFD);
exit(EXIT_FAILURE);
}
/* perform read write operations ... */
recvlambda(SocketFD);
(void) shutdown(SocketFD, SHUT_RDWR);
close(SocketFD);
return EXIT_SUCCESS;
}
int main(int argc, char** argv)
{
if(argc>1 && strcmp(argv[1], "server")==0)
server();
else
client();
return 0;
}
【问题讨论】:
-
你不能像这样简单地通过套接字传递
read和write对象,除了可简单复制的类型,比如 C 中的那些。你知道如果你以正确的方式发送char*会发生什么? (不是它指向的,指针本身)。同样的事情。 -
1.您可以(并且应该)使用
auto来声明f2. 无需使其可变,您永远不会修改内部状态 3. 您说它返回int但事实并非如此。当然,4. 你不能返回一个局部变量的地址(这就是一个 lambda,真的) -
还要注意这里的问题不是lambda本身,而是
function<int(void)>保持状态。 -
@MooingDuck 可变和返回 int 是我的错误,我应该删除它们。尽管如此,这对我的问题没有任何影响。此外,您对 char* 的评论在这里无效,因为我没有复制任何指针。
-
@rosewater:不正确,您正在复制指针。现在想象一下:
struct player {const char* name;}显然读/写player也是无效的,对吗?好吧,function<int(void)>内部同样包含一个指针。