C Socket 编程,select() 和 fd_set 的问题
我正在学习用 C 语言进行套接字编程(参考 Beej)。
这是我正在尝试实现的一个简单的多用户聊天服务器: http://pastebin.com/gDzd0WqP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#define MSG_SIZE 1024
#define LISTEN_Q 32
struct sockFDList {
int sockFD;
struct sockFDList *next;
};
int main(int argc, char *argv[]) {
int listenFD, newFD, fdmax, i; // listenFD for listening, newFD for new connection
char msg[MSG_SIZE]; // buffer for msg transmit
struct addrinfo hints, *myAI; // address info
struct sockaddr_storage remoteAddr; // store client address
socklen_t sizeAddr; // sizeof client address
fd_set masterSet, readSet; // FD sets for list and read.
// Clear Sets
FD_ZERO(&masterSet);
FD_ZERO(&readSet);
// Clear hints
memset(&hints, 0, sizeof hints);
// Prep hints
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
// Get local addr info
getaddrinfo("localhost", argv[1], &hints, &myAI);
// Get socket for listening
listenFD = socket(myAI->ai_family, myAI->ai_socktype, myAI->ai_protocol);
// Bind socket sockFD
bind(listenFD, myAI->ai_addr, myAI->ai_addrlen);
// Add sfd to master set
FD_SET(listenFD, &masterSet);
// Initialize fdmax
fdmax = listenFD;
while(1) {
// Copy master
readSet = masterSet;
// call select
if(select(fdmax+1, &readSet, NULL, NULL, NULL) == -1)
continue;
// loop through readSet
for(i=0; i<=fdmax; i++) {
if(FD_ISSET(i, &readSet)) { // Active !
if(i == listenFD) { // If listener socket
// New Connection, accept
sizeAddr = sizeof remoteAddr;
newFD = accept(listenFD, (struct sockaddr *)&remoteAddr, &sizeAddr);
printf("\n");
// Add this connection to my master list
FD_SET(newFD, &masterSet);
// update fdmax
if(newFD > fdmax)
fdmax = newFD;
}
else {
// Something to read on a socket
recv(i, msg, MSG_SIZE, 0);
msg[MSG_SIZE] = '\0';
// print it.
printf("%s\n",msg);
}
}
}
}
return 0;
}
在运行时,它给出总线错误。它来自第 68-78 行。
帮我追查问题的根源吗?
事实上,为什么我的代码甚至到达了那个特定区域?我刚刚运行了服务器。没有客户端连接..:@
ps - 我知道我的代码非常不可靠(任何地方都没有错误检查),但我会在稍后阶段这样做;我只是想在实现它的全部荣耀之前测试代码的功能;)
I'm learning my way about socket programming in C (referring to Beej).
Here is a simple multi-user chat server i'm trying to implement:
http://pastebin.com/gDzd0WqP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#define MSG_SIZE 1024
#define LISTEN_Q 32
struct sockFDList {
int sockFD;
struct sockFDList *next;
};
int main(int argc, char *argv[]) {
int listenFD, newFD, fdmax, i; // listenFD for listening, newFD for new connection
char msg[MSG_SIZE]; // buffer for msg transmit
struct addrinfo hints, *myAI; // address info
struct sockaddr_storage remoteAddr; // store client address
socklen_t sizeAddr; // sizeof client address
fd_set masterSet, readSet; // FD sets for list and read.
// Clear Sets
FD_ZERO(&masterSet);
FD_ZERO(&readSet);
// Clear hints
memset(&hints, 0, sizeof hints);
// Prep hints
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
// Get local addr info
getaddrinfo("localhost", argv[1], &hints, &myAI);
// Get socket for listening
listenFD = socket(myAI->ai_family, myAI->ai_socktype, myAI->ai_protocol);
// Bind socket sockFD
bind(listenFD, myAI->ai_addr, myAI->ai_addrlen);
// Add sfd to master set
FD_SET(listenFD, &masterSet);
// Initialize fdmax
fdmax = listenFD;
while(1) {
// Copy master
readSet = masterSet;
// call select
if(select(fdmax+1, &readSet, NULL, NULL, NULL) == -1)
continue;
// loop through readSet
for(i=0; i<=fdmax; i++) {
if(FD_ISSET(i, &readSet)) { // Active !
if(i == listenFD) { // If listener socket
// New Connection, accept
sizeAddr = sizeof remoteAddr;
newFD = accept(listenFD, (struct sockaddr *)&remoteAddr, &sizeAddr);
printf("\n");
// Add this connection to my master list
FD_SET(newFD, &masterSet);
// update fdmax
if(newFD > fdmax)
fdmax = newFD;
}
else {
// Something to read on a socket
recv(i, msg, MSG_SIZE, 0);
msg[MSG_SIZE] = '\0';
// print it.
printf("%s\n",msg);
}
}
}
}
return 0;
}
On runtime, it gives Bus Error. It's coming from the lines 68-78.
Help me trace the source of the problem?
in fact, WHY is my code even REACHING that particular region? I've just run the server. no clients have connected.. :@
ps - I know my code is highly unreliable (no error checks anywhere), but I WILL do that at a later stage; I just want to TEST the functionality of the code before implementing it in all it's glory ;)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
第 81 行
超出了你的缓冲区。 你还需要
检查所有可能失败的调用的返回值,即第39、42、45、68和80行
编辑:如果你检查了错误,很可能你' d 看到accept() 调用失败,可能是由于套接字未处于监听模式 - 也就是说,您错过了对
listen()
的调用line 81
overruns your buffer. Make it
You also need to check the return value of all the calls that can fail, that's line 39,42,45,68 and 80
Edit: And if you'd checked for errors, likely you'd seen the accept() call fail, likely due to the socket not being in listen mode - that is, you're missing a call to
listen()
另一件需要考虑的事情是,您不一定可以通过简单的赋值来复制
fd_set
变量。处理它们的唯一可移植方法是通过每次循环活动文件描述符列表来从头开始重新生成fd_set
。Another thing to consider is that you can't necessarily copy
fd_set
variables by simple assignment. The only portable way to handle them is to regenerate thefd_set
from scratch by looping over a list of active file descriptors each time.