socket

在做一个简单的socket程序时,遇到当client退出时,server状态为defunct情况。过程如下:

 (1)   Server  <--  Client

 (2)   Server (accept) <-X- Client
                   (fork)             |
             New Server  <-----+

 (3)   Server            杀掉Client后
        New Server <defunct>

原因:在子进程退出时,发送了SIGCHLD信号。

解决方法在父进程中waitpid(); 可以获得子进程的退出状态


void sig_chld (int signo) {
    pid_t pid;
    int stat;

    while ((pid = waitpid(-1,&stat, WNOHANG)) > 0)
        printf("child %d terminated\n",pid);
    return;
}

int main()
{
signal(SIGCHLD, sig_chld);
//...
fork();
}

 也可以在父进程中忽略该信号

signal(SIGCHLD,SIG_IGN); 

下面是几个socket用到的属性介绍. 

int socket(int domain, int type, int protocol);

/* int type SOCK_CLOEXEC: 这个属性对应open函数的O_CLOEXEC 该标志作用为,当执行fork并执行exec的时候,在子进程中,自动关闭此描述符
参考:http://blog.csdn.net/chrisniu1984/article/details/7050663
*/ /* 也可以通过如下代码设置 */
int v;
v
= fcntl(fd, F_GETFD, 0);
fcntl(fd, F_SETFD, v
|FD_CLOEXEC);


/* SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口,整个相关五元组还是唯一确定的。
* 所以,重启后的服务程序有可能收到非期望数据。必须慎重使用 SO_REUSEADDR 选项。
* 如果你的服务程序停止后想立即重启,而新套接字依旧使用同一地址和端口,此时 SO_REUSEADDR 选项非常有用。
*/

setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));


/* fcntl(fd, F_SETFL, O_NONBLOCK);
* 如果socket设置了如上属性,那么accept也将是非阻塞的。accept()函数会立即返回。
* 注:没有数据时,会返回错误。
*/

accept(s->fd, (struct sockaddr*)&cliaddr, &clilen);

 

read 收包,判断是否一个接收已经完成了。

/* 文件,socket 同理,read返回0时,才表示文件尾/数据包尾 */
while(read(sock, buf, sizeof(buf)-1))
{
  //数据放入缓冲区
}
/***********************************
同时有如下内部逻辑
TCP协议是面向流的,read和write调用的返回值往往小于参数指定的字节数。对于read调用,
如果接收缓冲区中有20字节,请求读100个字节,就会返回20。对于write调用,如果请求写100个字节,
而发送缓冲区中只有20个字节的空闲位置,那么write会阻塞,直到把100个字节全部交给发送缓冲区才返回,
但如果socket文件描述符有O_NONBLOCK标志,则write不阻塞,直接返回20
***********************************/

 

posted on 2013-03-27 14:54  cfox  阅读(590)  评论(0编辑  收藏  举报

导航