socket(三)

来源:互联网 发布:mac eclipse gbk 编辑:程序博客网 时间:2024/06/05 19:07

一、REUSEADDR

    服务器端关闭,再重新启动时又要去重新绑定地址,但此时网络仍处于TIME_WAIT状态,无法重新绑定。解决的办法就是服务器在绑定前调用setsockopt来设置REUSEADDR套接字选项。它可以使不必等待TIME_WAIT状态消失就可以重启服务器。

int on=1;if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)    ERROR_EXIT("setsockopt");

二、点对点的聊天程序

服务器端:
#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m)  \        do \        { \perror(m); \exit(EXIT_FAILURE); \        } while(0)int main(void){int listenfd;if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0)ERR_EXIT("socket");struct sockaddr_in addr;memset(&addr,0,sizeof(addr));addr.sin_family=AF_INET;addr.sin_port=htons(5188);addr.sin_addr.s_addr=htonl(INADDR_ANY);    /*addr.sin_addr.s_addr=inet_addr(127.0.0.1);  inet_aton("127.0.0.1",&addr.sin_addr);*/int on=1;if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)ERR_EXIT("setsockopt");if(bind(listenfd,(struct sockaddr*)&addr,sizeof(addr))<0)ERR_EXIT("bind");if(listen(listenfd,SOMAXCONN)<0)ERR_EXIT("listen");struct sockaddr_in peeraddr;socklen_t peerlen=sizeof(peeraddr);int conn;if((conn=accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0)ERR_EXIT("accept");printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));    pid_t pid;pid=fork();if(pid==-1)ERR_EXIT("fork");if(pid==0){char sendbuf[1024];while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL){write(conn,sendbuf,strlen(sendbuf));memset(sendbuf,0,sizeof(sendbuf));}exit(EXIT_SUCCESS);}else{char recvbuf[1024];while (1){memset(recvbuf,0,sizeof(recvbuf));int ret=read(conn,recvbuf,sizeof(recvbuf));if (ret==-1){ERR_EXIT("read");}else if(ret==0){printf("peer close\n");break;}fputs(recvbuf,stdout);}exit(EXIT_SUCCESS);}close(listenfd);close(conn);return 0;}
客户端:
#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m)  \        do \        { \perror(m); \exit(EXIT_FAILURE); \        } while(0)int main(void){int sock;if((sock=socket(AF_INET,SOCK_STREAM,0))<0)ERR_EXIT("socket");struct sockaddr_in servaddr;memset(&servaddr,0,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(5188);servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");    /*addr.sin_addr.s_addr=inet_addr(127.0.0.1);  inet_aton("127.0.0.1",&addr.sin_addr);*/if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)ERR_EXIT("connect");pid_t pid;pid=fork();if(pid==-1)ERR_EXIT("fork");if(pid==0){char sendbuf[1024];while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL){write(sock,sendbuf,strlen(sendbuf));memset(sendbuf,0,sizeof(sendbuf));}exit(EXIT_SUCCESS);}else{char recvbuf[1024];while (1){memset(recvbuf,0,sizeof(recvbuf));int ret=read(sock,recvbuf,sizeof(recvbuf));if (ret==-1){ERR_EXIT("read");}else if(ret==0){printf("peer close\n");break;}fputs(recvbuf,stdout);}exit(EXIT_SUCCESS);}close(sock);return 0;}

三、上述程序中存在的问题

    上述代码客户端和服务器都使用子进程处理输入,而父进程处理从对方接受数据,当接受数据大小为0时,父进程退出。实际上子进程仍在残留,可以使用信号的方法通知子进程,子进程收到信号后退出。这是用信号的方式进程进程间通信。
#include <signal.h>void handler(int sig){printf("recv a sig=%d\n",sig);exit(EXIT_SUCCESS);}signal(SIGUSR1,handler);//子进程中kill(pid, STGUR1);//父进程中/*子进程通知父进程signal(SIGUSR1,handler);kill(getppid(), STGUR1);*/





0 0