很多socket编程的初学者可能会遇到这样的问题:如果先ctrl+c结束服务器端程序的话,再次启动服务器就会出现Address already in use这个错误,或者你的程序在正常关闭服务器端socket后还是有这个问题。正如下面的这段简单的socket程序。

server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h> #define BUFFER_SIZE 40 int main()
{
char buf[BUFFER_SIZE];
int server_sockfd, client_sockfd;
int sin_size=sizeof(struct sockaddr_in);
struct sockaddr_in server_address;
struct sockaddr_in client_address;
memset(&server_address,0,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(12000);
// 建立服务器端socket
if((server_sockfd = socket(AF_INET, SOCK_STREAM, 0))<0)
{
perror("server_sockfd creation failed");
exit(EXIT_FAILURE);
}
// 将套接字绑定到服务器的网络地址上
if((bind(server_sockfd,(struct sockaddr *)&server_address,sizeof(struct sockaddr)))<0)
{
perror("server socket bind failed");
exit(EXIT_FAILURE);
}
// 建立监听队列
listen(server_sockfd,5);
// 等待客户端连接请求到达
client_sockfd=accept(server_sockfd,(struct sockaddr *)&client_address,(socklen_t*)&sin_size);
if(client_sockfd<0)
{
perror("accept client socket failed");
exit(EXIT_FAILURE);
}
// 接收客户端数据
if(recv(client_sockfd,buf,BUFFER_SIZE,0)<0)
{
perror("recv client data failed");
exit(EXIT_FAILURE);
}
printf("receive from client:%s/n",buf);
// 发送数据到客户端
if(send(client_sockfd,"I have received your message.",BUFFER_SIZE,0)<0)
{
perror("send failed");
exit(EXIT_FAILURE);
}
close(client_sockfd);
close(server_sockfd);
exit(EXIT_SUCCESS);
}

client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h> #define BUFFER_SIZE 40 int main()
{
char buf[BUFFER_SIZE];
int client_sockfd;
int len;
struct sockaddr_in address;// 服务器端网络地址结构体
int result;
client_sockfd = socket(AF_INET, SOCK_STREAM, 0);// 建立客户端socket
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(12000);
len = sizeof(address);
// 与远程服务器建立连接
result = connect(client_sockfd, (struct sockaddr *)&address, len);
if(result<0)
{
perror("connect failed");
exit(EXIT_FAILURE);
}
printf("Please input the message:");
scanf("%s",buf);
send(client_sockfd,buf,BUFFER_SIZE,0);
recv(client_sockfd,buf,BUFFER_SIZE,0);
printf("receive data from server: %s/n",buf);
close(client_sockfd);
return 0;
}

在成功的运行了第一次之后,当你再次启动服务器端程序时,./server就变得邪恶起来,在bind()这个函数中居然出现了Address already in use这个错误。

然后你开始迷惑了,难道是忘记将socket给关闭了,或是关闭socket的顺序不对?经过种种猜测与试验,你发现问题毫无进展......过了一会,当你再次抱着试试看的态度重新在linux的“黑色终端”中输入./server时,程序居然运行了,什么情况?究其原因,是socket选项在捣鬼。下面是IBM官网上对这一情况的具体解释,参见http://www.ibm.com/developerworks/cn/linux/l-sockpit/

bind 普遍遭遇的问题是试图绑定一个已经在使用的端口。该陷阱是也许没有活动的套接字存在,但仍然禁止绑定端口(bind 返回 EADDRINUSE),它由 TCP 套接字状态 TIME_WAIT 引起。该状态在套接字关闭后约保留 2 到 4 分钟。在 TIME_WAIT 状态退出之后,套接字被删除,该地址才能被重新绑定而不出问题。

等待 TIME_WAIT 结束可能是令人恼火的一件事,特别是如果您正在开发一个套接字服务器,就需要停止服务器来做一些改动,然后重启。幸运的是,有方法可以避开 TIME_WAIT 状态。可以给套接字应用 SO_REUSEADDR 套接字选项,以便端口可以马上重用。

考虑清单 3 的例子。在绑定地址之前,我以 SO_REUSEADDR 选项调用 setsockopt。为了允许地址重用,我设置整型参数(on)为 1 (不然,可以设为 0 来禁止地址重用)。

按照IBM的做法,我重新改写了server.c的代码。

server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h> #define BUFFER_SIZE 40 int main()
{
char buf[BUFFER_SIZE];
int server_sockfd, client_sockfd;
int sin_size=sizeof(struct sockaddr_in);
struct sockaddr_in server_address;
struct sockaddr_in client_address;
memset(&server_address,0,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(12000);
// 建立服务器端socket
if((server_sockfd = socket(AF_INET, SOCK_STREAM, 0))<0)
{
perror("server_sockfd creation failed");
exit(EXIT_FAILURE);
}
// 设置套接字选项避免地址使用错误
int on=1;
if((setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)
{
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
// 将套接字绑定到服务器的网络地址上
if((bind(server_sockfd,(struct sockaddr *)&server_address,sizeof(struct sockaddr)))<0)
{
perror("server socket bind failed");
exit(EXIT_FAILURE);
}
// 建立监听队列
listen(server_sockfd,5);
// 等待客户端连接请求到达
client_sockfd=accept(server_sockfd,(struct sockaddr *)&client_address,(socklen_t*)&sin_size);
if(client_sockfd<0)
{
perror("accept client socket failed");
exit(EXIT_FAILURE);
}
// 接收客户端数据
if(recv(client_sockfd,buf,BUFFER_SIZE,0)<0)
{
perror("recv client data failed");
exit(EXIT_FAILURE);
}
printf("receive from client:%s/n",buf);
// 发送数据到客户端
if(send(client_sockfd,"I have received your message.",BUFFER_SIZE,0)<0)
{
perror("send failed");
exit(EXIT_FAILURE);
}
close(client_sockfd);
close(server_sockfd);
exit(EXIT_SUCCESS);
}

这次,让我们再次反复的启动服务器,尽情的在“黑窗户”里面输入./server ./server ./server ......服务器的程序好像突然间变乖了,呵呵,童鞋们,为自己的成就庆祝吧!!!

地址已经被使用 - Address already in use的更多相关文章

  1. socket编程小问题:地址已经被使用——Address already in use

    很多socket编程的初学者可能会遇到这样的问题:如果先ctrl+c结束服务器端程序的话,再次启动服务器就会出现Address already in use这个错误,或者你的程序在正常关闭服务器端so ...

  2. WCF :IIS寄宿方式的Web地址、BaseAddress和EndPoint Address的关系

    对于在IIS中通过W3SVC或WAS寄宿的WCF Service,其在浏览器中显示的地址(Web地址),与其配置文件中的BaseAddress和EndPoint Address有什么关系呢?让我们来分 ...

  3. 获取本机IP地址

    这里有两种方法: //获取本机IP - (NSString *)localIPAddress { NSString *localIP = nil; struct ifaddrs *addrs; ) { ...

  4. Java里面获取当前服务器的IP地址

    public static void main(String[] args) { try { InetAddress address = InetAddress.getLocalHost();//获取 ...

  5. 实验1_IPv6地址配置

    IPv6地址配置 实验任务 (1)掌握如何在路由器及PC上配置IPv6地址 (2)掌握如何用IPv6 ping命令进行IPv6地址可达性检查 (3)掌握如何用命令来查看IPv6地址配置 实验过程 在R ...

  6. 语义化HTML:p、h1-6、q、blockquote、hr、address、code、pre、var、cite、dfn和samp

    一.元素语义 p标签 W3C草案: The p element represents a paragraph.W3C specification 语义化的 <p>元素 表示:文章中的段落. ...

  7. [PE结构分析] 8.输入表结构和输入地址表(IAT)

    在 PE文件头的 IMAGE_OPTIONAL_HEADER 结构中的 DataDirectory(数据目录表) 的第二个成员就是指向输入表的.每个被链接进来的 DLL文件都分别对应一个 IMAGE_ ...

  8. php读取qqwry.dat ip地址定位文件的类

    <?php// +----------------------------------------------------------------------// |// +---------- ...

  9. 纯真IP根据IP地址获得地址

    <?php /** * 纯真IP根据IP地址获得地址 */ class ipLocation { public $fp; public $firstip; //第一条ip索引的偏移地址 publ ...

随机推荐

  1. DIV-CSS布局中position属性详解

    本文向大家描述一下DIV CSS布局中的position属性的用法,position属性主要有四种属性值,任何元素的默认position的属性值均是static,静态.这节课主要讲讲relative( ...

  2. python3 识别图片文字

    1.下载相关组件 安装:pip install Pillow 或下载:https://pypi.org/project/Pillow/5.2.0/  ,https://pypi.org/project ...

  3. java 切图 判断图片是否是纯色/彩色图片

    首先上切图的代码 /** * 图片剪裁 * @param x 距离左上角的x轴距离 * @param y 距离左上角的y轴距离 * @param width 宽度 * @param height 高度 ...

  4. mobile移动网页开发常用代码模板

    index.html <!DOCTYPE HTML> <html> <head> <!--申明当前页面的编码集--> <meta http-equ ...

  5. [AngularJS] Angular 1.3 ngMessages with ngAnimate

    Note: Can use $dirty to check whether user has intracted with the form: https://docs.angularjs.org/a ...

  6. [Node.js]31. Level 7: Redis coming for Node.js, Simple Redis Commands

    Let's start practicing using the redis key-value store from our node application. First require the  ...

  7. perl install-module.pl DateTime 执行无效问题的解决

    运行./checksetup.pl,总说DateTime模块需要安装,但是执行提示的perl install-module.pl DateTime 多次也还是说DateTime模块需要安装. 在神奇的 ...

  8. jQuery和CSS3超酷表单美化插件

     这是一款效果很精美炫酷的jQuery和CSS3联系方式表单美化插件.大多数站点上都有让用户填写的联系方式表单,一个设计良好的表单可以大大的提升用户的体验度.该表单美化插件在原生HTML表单的基础上进 ...

  9. DataGrid前台数据绑定技巧

    (1)DataGrid控件不换行,数据显示不完全后面加"..." <%# DataBinder.Eval(Container.DataItem,? DataBinder.Ev ...

  10. xhEditor在线编辑器使用实例

    使用xhEditor的最大好处就是不用去处理烦人的HTML标签问题,研究了一天,记录备用 前台HTML: <%@ Page Language="C#" AutoEventWi ...