使用TCP/UDP socket面试题调试工具怎么连接cpu1200

&使用Socket套接字进行编程,完成的是基于TCP可靠服务实现服务器与客户端的双通信。
package com.
import java.awt.C
import java.awt.event.ActionE
import java.awt.event.ActionL
import java.awt.event.WindowA
import java.awt.event.WindowE
import java.io.*;
import java.net.*;
import javax.swing.JD
import javax.swing.JScrollP
import javax.swing.JTextA
import javax.swing.JTextF
* 本程序实现了一个TCP程序的服务器编程部分。
* 使用Socket套接字进行编程,完成的是基于TCP可靠服务实现与客户端的双通信。
* 客户端的编程见本包中的类Client
* @author HAN
@SuppressWarnings(&serial&)
public class Server extends JDialog{
private BufferedR
private PrintW
private ServerS
private JTextArea ta=new JTextArea();
private JScrollPane sp=new JScrollPane(ta);
private JTextField tf=new JTextField();
public Server(String title) {
setTitle(title);
addWindowListener(new WindowAdapter() {
public void windowClosing (WindowEvent we) {
dispose();
//撤销dialog一切相关资源
System.exit(0); //正常退出程序
cc=getContentPane();
setLayout(null);
ta.setLineWrap(true);
ta.setEditable(false);
sp.setBounds(0,0,300,342);
tf.setBounds(0,342,300,25);
cc.add(sp);
cc.add(tf);
tf.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
writer=new PrintWriter(socket.getOutputStream(),true);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
writer.println(tf.getText());
ta.append(&User1:&+tf.getText()+'\n');
tf.setText(&&);
void getserver(){
server=new ServerSocket(8998);
ta.append(&服务器套接字已经创建成功\n&);
while(true){
ta.append(&等待客户机的连接\n&);
socket=server.accept();
ta.append(&客户机已连接\n&);
reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
getClientMessage();
}catch(Exception e){
e.printStackTrace();
private void getClientMessage(){
while(true){
String news=reader.readLine();
if(news!=null){
ta.append(&User2:&+news+&\n&);
ta.append(&User2(客户端) 已断开链接\n&);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if(reader!=null){
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if(socket!=null){
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
public static void main(String[] args) {
Server user1=new Server(&User1&);
user1.setBounds(0,0,300,400);
user1.setResizable(false);
user1.setVisible(true);
user1.getserver();
package com.
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
* 本程序实现了一个TCP程序的客户端编程部分。
* 使用Socket套接字进行编程,完成的是基于TCP可靠服务实现与服务器的双通信。
* 服务器的编程见本包中的类Server
* 可以在不同的平台与不同的机器上运行,只是要把代码中写的IP地址修改为运行服务器程序Server的机器的IP地址。
* @author HAN
@SuppressWarnings(&serial&)
public class Client extends JDialog{
private BufferedR
private PrintW
private JTextArea ta=new JTextArea();
private JScrollPane sp=new JScrollPane(ta);
private JTextField tf=new JTextField();
public Client(String title) {
setTitle(title);
addWindowListener(new WindowAdapter() {
public void windowClosing (WindowEvent we) {
dispose();
//撤销dialog一切相关资源
System.exit(0); //正常退出程序
cc=getContentPane();
setLayout(null);
ta.setLineWrap(true);
ta.setEditable(false);
sp.setBounds(0,0,300,342);
tf.setBounds(0,342,300,25);
cc.add(sp);
cc.add(tf);
tf.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
writer.println(tf.getText());
ta.append(&User2:&+tf.getText()+'\n');
tf.setText(&&);
private void connect(){
ta.append(&尝试连接\n&);
socket=new Socket(&192.168.1.3&,8998);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
writer=new PrintWriter(socket.getOutputStream(),true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ta.append(&完成连接\n&);
private void getClientMessage(){
reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true){
String news=reader.readLine();
if(news!=null){
ta.append(&User1:&+news+&\n&);
ta.append(&User1(服务器) 已断开链接,等待服务器重连之时,重启User2(客户端)进行通信\n&);
} catch (IOException e) {
// TODO Auto-generated catch block
ta.append(&User1(服务器) 已断开链接,等待服务器重连之时,重启User2(客户端)进行通信\n&);
e.printStackTrace();
if(reader!=null){
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if(socket!=null){
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
public static void main(String[] args) {
Client user2=new Client(&User2&);
user2.setBounds(0,0,300,400);
user2.setVisible(true);
user2.setResizable(false);
user2.connect();
user2.getClientMessage();
随笔 - 534关于UDP接收icmp端口不可达(port unreachable)
有时候,写UDP socket程序的时候,在调用sendto或者recvfrom的时候,会发现有Connection refused错误返回,错误码是ECONNREFUSED。对于懂得socket接口但是不很很懂网络的人,可能这根本就不是个问题,他会根据错误码知道远端没有这个服务端口,正如socket api的man手册中描述的那样:
ECONNREFUSED
A remote host refused to allow the network connection (typically because it is not running the requested service).
有时候无知真的是一种幸福!但是如果你十分精通TCP/IP栈,那么就想不通了,UDP既然无连接,怎么知道远端的情况呢?UDP不正如协议标准描述的那样,发出去就不管了吗?对于接收,没有数据就一直等,如果设置了NOWAIT,则直接返回EAGAIN,表示稍后再试。不管怎么说,也不会有ECONNREFUSED这么详细的信息返回才对啊。
既然UDP不会从对端返回任何错误信息,那么一定有别的什么返回了,总不能凭空猜测啊。这就涉及到了网络协议设计中的数据平面和控制平面了,对于控制平面的消息,可以是带内传输,也可以是带外传输。对于TCP而言,无疑是带内传输的,因为它本身就是有连接的协议,协议本身会处理任何的错误和异常,然而对于UDP而言,因为其设计目的就是保持简单性,故不再附带有任何带内的控制消息逻辑,互联网上为了弥补这一类协议的控制逻辑的缺失,ICMP协议才显得尤为重要!实际上,ICMP,根据名称就可以看出它是一种专门的控制协议,控制和指示IP层发生的事件。
ECONNREFUSED正是ICMP返回的!然而并不是所有的UDP socket都可以享用ICMP带来的错误提示,毕竟带外控制消息和协议本身的关联太松散了。UDP socket必须显式的connect对端才可以。现在问题又来了,既然UDP根本就是一个无连接的协议,connect的意义何在呢?这其实是socket接口设计的范畴,和协议本身没有任何关系,当一个UDP socket去connect一个远端时,并没有发送任何的数据包,其效果仅仅是在本地建立了一个五元组映射,对应到一个对端,该映射的作用正是为了和UDP带外的ICMP控制通道捆绑在一起,使得UDP socket的接口含义更加丰满。
我们知道,ICMP错误信息返回时,ICMP的包内容就是出错的那个原始数据包,根据这个原始数据包可以找出一个五元组,根据该五元组就可以对应到一个本地的connect过的UDP socket,进而把错误消息传输给该socket,应用程序在调用socket接口函数的时候,就可以得到该错误消息。如果一个UDP socket没有调用过connect,那么即使有ICMP数据包返回,由于socket保持了UDP的完整语义,协议栈也就不保存关于该socket和对端关联的任何信息,因此也就无法找到一个特定的五元组将错误码传给它。
以下是一个测试程序:
void&test(&int&sd,&struct&sockaddr&*addr,&socklen_t&len)
char&buf[4];
connect(sd,&(struct&sockaddr&*)addr,&len);
sendto(sd,&buf,&4,&0,&(struct&sockaddr&*)addr,&len);
perror("write");
sendto(sd,&buf,&4,&0,&(struct&sockaddr&*)addr,&len);
perror("write");
recvfrom(sd,&buf,&4,&0,&(struct&sockaddr&*)addr,&len);
perror("read");
int&main(int&argc,&char&**argv)
struct&sockaddr_in&
if(argc&!=&2)&{
bzero(&addr,&sizeof(addr));
addr.sin_family&=&AF_INET;
addr.sin_port&=&htons(12345);
inet_pton(AF_INET,&argv[1],&&addr.sin_addr);
sd&=&socket(AF_INET,&SOCK_DGRAM,&0);
test(sd,&(struct&sockaddr&*)&addr,&sizeof(addr));
编译为UDPclient,执行./UDPclient 192.168.1.20,注意,这个地址一定要是个IP可达的地址,才好测试。按照上面的理论,结果应该是:第一个sendto成功,然后192.168.1.20返回了:
ICMP 192.168.1.20 udp port 12345 unreachable, length 40
接下来第二个sendto返回:
write: Connection refused
由于第二次没有发送任何数据包到达192.168.1.20,所以也不能企望它返回ICMP错误信息,因此接下来的recvfrom调用会阻塞。
最后的一个问题时,你不能太指望这个Connection refused以及一切带外返回的错误信息,因为你不能保证一定能收到远端发送的ICMP包,如果中间的某个节点或者本机禁掉了ICMP,socket api调用就无法捕获这些错误。
本文将讲解为什么服务器回复端口不可达,以及客户端socket 如何获取 端口不可达 信号。
首先,做为服务器,当一个报文经过查路由,目的ip是上送本机的时候,经过netfilter 判决后,
调用ip_local_deliver_finish,它根据ip头中的协议类型(TCP/UDP/ICMP/......),调用不同的4层接口函数进行处理。
对于udp而言,handler 是udp_rcv,它直接调用了__udp4_lib_rcv,查找相应的sock,
如果sk不存在if(sk != NULL),就回复icmp destination unreachable,函数非常简单
所以作为服务器,收到一个目的端口并未监听的报文,直接回复端口不可达。
那么作为客户端,如何处理服务器回复的 端口不可达 报文呢?
起始当初想法很简单,我认为,不同的协议之间是不会干涉的,即TCP和UDP直接是不会干涉的。
何况这种不伦不类的icmp?后来想错了。
作为客户端,端口不可达报文进入ip_local_deliver_finish,它调用icmp_rcv函数,进行处理。(其实这也是当初
我认为客户端udp不会对端口不可达数据进行相应的原因,因为udp处理流程是udp_rcv)。
icmp_rcv函数最重要的是 它调用了:icmp_pointers[icmph-&type].handler(skb);
handler&= icmp_unreach
icmp_unreach函数最终的一步,就是它最后一步:
是不是很像ip_local_deliver_finish?
是很像,只是ip_local_deliver_finish中,调用了ipprot-&handler,而这里调用了ipprot-&err_handler
对于udp,err_handler&= udp_err = __udp4_lib_err
在该函数中,只有进入如下的流程,应用程序才会反应:
先决条件是inet-&recverr为非0,或者inet-&recverr为0但是udp处于TCP_ESTABLISHED状态。
否则应用程序休想收到该端口不可达的数据,应用程序就等着read超时吧。所以说,为了获取udp端口不可达的情况
有2种方法:
对udp进行connect操作,并且将sendto改成send
int val = 1;
setsockopt(fd, IPPROTO_IP, IP_RECVERR , &val,sizeof(int));
udp获知端口不可达的源程序
unsigned&charrevc_buf[1024];
intfd,ret,recv_len,size=1024;
structsockaddr_in&server_addr,
intval&=&1;
server_addr.sin_family&=&AF_INET;
server_addr.sin_addr.s_addr&=&inet_addr("192.168.2.254");
server_addr.sin_port&=&htons(77);
fd&=&socket(AF_INET,&SOCK_DGRAM,&IPPROTO_UDP);
if(fd&&&0)
perror("socket&fail&");
printf("socket&sucess\n");
setsockopt(fd,&IPPROTO_IP,&IP_RECVERR&,&&val,sizeof(int));
if(sendto(fd,"nihao",&strlen("nihao"),&0,&(conststructsockaddr&*)&(server_addr),sizeof(structsockaddr_in))&0)
perror("sendto&fail&");
printf("sendto&sucess\n");
recv_len&=&recvfrom(fd,&revc_buf,&sizeof(revc_buf),&0,&(structsockaddr&*)&addr,&(int*)&size);
printf("recv_len:%d&sucess\n");
"font-size:18"&"code"class="cpp"&//方法1
ret&=&connect(fd,&(conststructsockaddr&*)&&(server_addr),sizeof(structsockaddr_in));
if(ret&&&0)
printf("connect&fail\n");
ret&=&send(fd,&"ni&hao",&strlen("nihao"),0);
if(ret&&&0)
printf("write&fail\n");
ret&=&recvfrom(fd,&revc_buf,&sizeof(revc_buf),&0,&(structsockaddr&*)&addr,&(int*)&size);
if(ret&&&0)
printf("read&fail\n");
close(fd);
12/15 04:37
ICMP差错报文的格式 不可达,超时,源泉抑制 type len cksum Void(必须是0) 被破坏分组的IP首部 需要分片 type len cksum Pmvoid(必须是0) nextmtu 被破坏分组的IP首部 参数问题 type len cksum pptr (必须是0) 被破坏分组的IP首部 信宿不可达报文类型表 代码值 类型描述 代码值 类型描述 0 网络不可达 7 信宿主机未知 1 主机不可达 8 信源主机被隔离 2 协议不可达 9 与信宿网络的通信被禁止 3 端口不可达
10/10 22:07
[DESCRIPTION]09B之前版本适用.需要在MMItask或者其他task中接收带端口号的短信[SOLUTION]InMMItask注册端口要接收一个数据短信,首先需要注册一个对应的端口:当收到该端口的SMS时,会调用注册的CallbackFunction.1API原型voidmmi_frm_sms_reg_port(PsFuncPtrU16callback,module_typemod_src,U16port_num,BOOLenable,BOOLwithoutdata,PsFuncP
06/27 12:02
今天有个做Linux开发的哥们问我怎么查看某个端口的流量,我之前还真很少查看某个端口的流量,都习惯查看某个网卡的流量.不过想了一下,这个肯定是可以的.马上想起我经常使用的iptraf工具,折腾了几分钟,方法如下,很简单: 1.终端里打开iptraf(没安装的自己安装,官方源有),选择 Configure -- Additional ports,然后输入端口范围,如果查看22,就输入22 -- 22,之后退出iptraf,如图所示: 2.重新打开iptraf,选择 Statistical bre
01/20 03:12
1.网络扫描简介 网络扫描是一种自动化程序,用于检测远程或本地主机的弱点和漏洞.漏洞扫描是入侵防范最基本的工作,攻击者正式利用各种漏洞入侵系统.借助自动化的扫描工作,在攻击者之前发现漏洞问题,并给予相应的修正程序. 一名攻击者入侵系统,一般分为四个步骤:系统发现,漏洞探测,漏洞利用和痕迹清除. 本文的重点就是在于系统发现与漏洞探测方面. 2.端口扫描技术 端口扫描能够用来查找目标主机已开放的端口,包括TCP和UDP端口.当前针对TCP端口的扫描技术有三种,分别为:全连接扫描,SYN扫描和FIN扫
11/09 22:55
如何对udp端口进行扫描 分类: 学习ipc
08:56 2199人阅读 评论(0) 收藏 举报
由于UDP协议是非面向连接的,对UDP端口的探测也就不可能像TCP端口的探测那样依赖于连接建立过程(不能使用telnet这种tcp协议类型命令),这也使得UDP端口扫描的可靠性不高.所以虽然UDP协议较之TCP协议显得简单,但是对UDP端口的扫描却是相当困难的.下面具体介绍一下UDP扫描方案:
方案1:利用ICMP端口不可达报文进行扫描
本方案的原理是
07/07 03:19
http://blog.csdn.net/jacky_jin/article/details/0 使用UDP的一些蕴含对于设计和实现服务器会产生影响.通常,客户端的设计和实现比服务器端的要容易一些,这就是我们为什么要讨论服务器的设计,而不是讨 论客户端的设计的原因.典型的服务器与操作系统进行交互作用,而且大多数需要同时处理多个客户.
通常一个客户启动后直接与单个服务器通信,然后就结束了.而对于服务器来说,它启动后处于休眠状态,等待客户请求的到来.对于UDP来说,当客
09/06 09:44
第11章 UDP:用户数据报协议 本书内容收集自网络,仅为方便个人学习和研究之用,版权归原书出版方所有,请支持正版. http://docs.52im.net/extend/docs/book/tcpip/vol1/11/ 11.1 引言 UDP是一个简单的面向数据报的运输层协议:进程的每个输出操作都正好产生一个UDP数据报,并组装成一份待发送的IP数据报.这与面向流字符的协议不同,如TCP,应用程序产生的全体数据与真正发送的单个IP数据报可能没有什么联系. UDP数据报封装成一份IP数据报的格
02/19 08:28
Linux协议栈中UDP数据报从网卡到用户空间流程总结 NAPI驱动流程:
--&确定中断原因是数据接收完毕(中断原因也可能是发送完毕,DMA完毕,甚至是中断通道上的其他设备中断)
--&通过netif_rx_schedule将驱动自己的napi结构加入softnet_data的poll_list链表,禁用网卡中断,并发出软中断
--&中断返回时触发软中断net_rx_action,从softnet_data的poll_list上取下刚挂入的na
08/11 18:59
1. ICMP协议格式 ICMP报文是在IP数据报内部传输的: | IP头部 | ICMP报文 | ICMP报文格式: Bits
Rest of Header Type – ICMP type as specified below. Code – Subtype to the given type. Checksum – Error c网络编程Socket之TCP之TIME_WAIT状态详解
下面我们用最简单的一对一的客户服务器模型来重现中遇到的一些问题:
初学socket的时候在编写socket程序的时候会遇到很多莫名其妙的问题,比如说bind函数返回的常见错误是EADDRINUSE
使用下面的程序重现这个状态:
int main(int argc, const char * argv[])
struct sockaddr_in serverA
bzero(&serverAdd, sizeof(serverAdd));
serverAdd.sin_family = AF_INET;
serverAdd.sin_addr.s_addr = inet_addr(SERV_ADDR);
serverAdd.sin_port = htons(SERV_PORT);
int connfd = socket(AF_INET, SOCK_STREAM, 0);
int connResult = connect(connfd, (struct sockaddr *)&serverAdd, sizeof(serverAdd));
if (connResult < 0) {
printf("连接失败\n");
close(connfd);
return -1;
ssize_t writeL
ssize_t readL
char recvMsg[65535] = {0};
char sendMsg[20] = "I am client";
writeLen = write(connfd, sendMsg, sizeof(sendMsg));
if (writeLen < 0) {
printf("发送失败\n");
close(connfd);
return -1;
printf("发送成功\n");
while (1) {
readLen = read(connfd, recvMsg, sizeof(recvMsg));
if (readLen < 0) {
printf("读取失败\n");
close(connfd);
return -1;
if (readLen == 0) {
printf("服务器关闭\n");
close(connfd);
return -1;
printf("server said:%s\n",recvMsg);
close(connfd);
int main(int argc, const char * argv[])
struct sockaddr_in serverA
struct sockaddr_in clientA
bzero(&serverAdd, sizeof(serverAdd));
serverAdd.sin_family = AF_INET;
serverAdd.sin_addr.s_addr = htonl(INADDR_ANY);
serverAdd.sin_port = htons(SERV_PORT);
socklen_t clientAddrL
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd < 0) {
printf("创建socket失败\n");
close(listenfd);
return -1;
int bindResult = bind(listenfd, (struct sockaddr *)&serverAdd, sizeof(serverAdd));
if (bindResult < 0) {
close(listenfd);
printf("绑定端口失败,errno = %d\n",errno);
return -1;
printf("绑定端口成功\n");
listen(listenfd, 20);
unsigned char recvMsg[65535];
char replyMsg[20] = "I am server";
clientAddrLen = sizeof(clientAdd);
connfd = accept(listenfd,(struct sockaddr *)&clientAdd,&clientAddrLen);
if (connfd < 0) {
close(listenfd);
printf("连接失败\n");
return -1;
printf("连接成功\n");
ssize_t readLen = read(connfd, recvMsg, sizeof(recvMsg));
printf("readLen:%ld\n",readLen);
if (readLen < 0) {
printf("读取失败\n");
return -1;
else if (readLen == 0) {
printf("读取完成\n");
close(listenfd);
replyMsg[readLen] = &#39;\0&#39;;
printf("client said:%s\n",replyMsg);
write(connfd, replyMsg, sizeof(replyMsg));
close(connfd);
首先运行服务器程序,再运行客户端,然后关闭服务端后立马再打开服务端,就会打印如下信息:48对应EADDRINUSE错误码
绑定端口失败,errno=
这里要说明一个问题:
当一个Unix进程无论自愿的(调用exit或者从main函数返回)还是非自愿的(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也将导致仍然打开的任何TCP连接上发出一个FIN。
很明显服务器已经关闭了,为什么会绑定端口失败呢,下面是TCP连接终止的四个分节:
某些情况下第一个分节的FIN随数据一起发送,另外,第二个和第三个分节有可能被合并成一个分节;vcD4KPHA+PGJyPgo8L3A+CjxwPjwvcD4KPHA+1eLA787Sw8e1xLf+zvHG98rH1ve2r7nYsdW1xNK7tsujrLWx1ve2r7eiy81GSU631r3a0tS687XItP3It8jPo6zXtMysseTOqkZJTl9XQUlUXzGjrMrVtb3It8jP0tS689e0zKyx5M6qRklOX1dBSVRfMqOsytW1vb/Nu6e2y7XERklOt9a92tLUuvPXtMysseTOqlRJTUVfV0FJVNe0zKyjrDxzdHJvbmc+1eLA79TaPC9zdHJvbmc+PHN0cm9uZz5USU1FX1dBSVTXtMysu+HNo8H0Mk1TTLrzssW74b34yOtDTE9TRUTXtMyso7vL+dLUztLDx9TZwaLC7cb0tq+3/s7xxve1xMqxuvKjrNaux7C1xMGsvdO7ucO709C0ptPaQ0xPU0VE17TMrKOsu7m05tTa1d+jrMv50tS+zbvhsPO2qMqnsNzBy6O7PC9zdHJvbmc+uvPD5rvhvbK1vc6qyrLDtLvhtObU2lRJTUVfV0FJVNe0zKyjuzwvcD4KPHA+1eLA77/Nu6e2y8rHsbu2r7nYsdW1xNK7tsujrMrVtb23/s7xtsu1xEZJTtauuvPXtMysvfjI60NMT1NFX1dBSVSjrNXiuPbKsbrycmVhZLe9t6i74be1u9gwo6zIu7rzt6LLzbbUtdrSu7j2t9a92rXEyLfIz6OstMvKsb/Nu6e2y7X308NjbG9zZbe9t6i3osvNRklOt9a92rj4t/7O8bbLvfjI60xBU1RfQUNL17TMrKOstci0/ci3yM+1vbTvo6zK1bW9yLfIz9LUuvPBrL3T17TMrLHkzqpDTE9TRUSjuzwvcD4KPHA+PGJyPgo8L3A+CjxwPjwvcD4KPHA+VElNRV9XQUlU17TMrKO6zaPB9NTauMPXtMystcSz1tD4yrG85MrH1+6zpLfWvdrJ+sP8xtqjqG1heGltdW0gc2VnbWVudCBsaWZldGltZaOsTVNMo6m1xMG9sbajrNPQyrG68rPGzqoyTVNMoaNNU0zKx8jOus5JUMr9vt2xqMTcubvU2tLyzNjN+NbQtOa77rXE1+6zpMqxvOSjrNfutPMmIzIwNTQwO86qMjU1o6zV4srH0ru49sz4yv3P3tbGtviyu8rH1ebV/bXEyrG85M/e1sajuzwvcD4KPHA+PGJyPgo8L3A+CjxwPjxzdHJvbmc+VElNRV9XQUlU17TMrLTm1NrA7dPJo7o8L3N0cm9uZz48L3A+CjxwPr/Jv7+12Mq1z9ZUQ1DIq8uruaTBrL3TtcTW1da5o7q/ycTcsru1w7K71ti0q9fu1tXEx7j2YWNro6xUSU1FX1dBSVS688rHQ0xPU0VEo6zI57n7w7vT0FRJTUVfV0FJVLXEMk1TTKOs1rG900NMT1NFRKOsxMfDtMjnufvX7rrz0ru49kFDS7aqyqfBy6Osyseyu7vh1tjQwtTZt6LLzUFDS7XEo6zEx7f+zvG2y8rVsru1vUFDS77Nu+HW2NDCt6LLzdfu1tXEx7j2RklOo6zV4rj2yrG68r/Nu6e2y9LRvq3Kx0NMT1NFRMHLo6y+zbvhz+zTptK7uPZSU1SjrNXiuPZSU1S+zbvhsbu3/s7xxve94srNs8nSu7j2tO3O86GjPC9wPgo8cD7UytDtwLS1xNbYuLS31r3a1NrN+MLn1tDP+8rFo7qxo9akw7+zybmmvajBotK7uPZUQ1DBrL3TyrGjrMC019S4w8GsvdPPyMewu6/J7bXEwM+1xNbYuLS31tfptrzS0b6t1NrN+MLn1tDP+8rFwcujrLTTtviyu7vhsbvO873is8nQwsGsvdO1xLfW1+mhozwvcD4KPHA+PGJyPgo8L3A+CjxwPtXiwO+7udPQ0rvW1sfpv/ajurTyv6q/zbuntst3aGlsZcDvw+a1xHNsZWVwo6yjqLvy1d/GwbHOtfS/zbuntsvPwsPmtcS0+sLro6nIu7rz1NnPyNTL0NC3/s7xxvezzNDyo6zU2dTL0NC/zbuntsujrMi7uvO52LHVt/7O8bbLuvPBosLt1Nm08r+qt/7O8bbLo6zI1Mi7u+Gw87aoyqew3KOstMvKsbXE17TMrLrN1q7HsLXE09C147K70rvR+TwvcD4KPHA+PC9wPgo8cD48L3A+CjxwcmUgY2xhc3M9"brush:">if (readLen == 0) {
printf("服务器关闭\n");
close(connfd);
return -1;
我们从终端打印信息如下,此时服务器处于FIN_WAIT_2状态,就如上面说的因为客户端还没有关闭连接,没有发送第三个FIN分节,此时客户端因为已经收到来自服务端的FIN分节而处于CLOSE_WAIT状态;
wanglijuntekiMac-mini:~ wanglijun$ netstat -an |grep 8000
192.168.1.103.8000
192.168.1.103.49632
FIN_WAIT_2
192.168.1.103.49632
192.168.1.103.8000
CLOSE_WAIT
解决方法:
这里有一个SO_REUSEADDR套接字选项,打开之后就能解决如上的问题,我们在band之前添加如下设置代码:
int yes = 1;
setsockopt(listenfd,
SOL_SOCKET, SO_REUSEADDR,
(void *)&yes, sizeof(yes));
服务器重启监听时,试图捆绑现有连接上的端口会失败,(还有一种情况可能之前派生出来的子进程还处理着连接)如果设置了SO_REUSEADDR套接字选项,就会bind成功,所有的TCP服务器都应该指定SO_REUSEADDR套接字选项,以允许服务器在这种情形下被重新启动;SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可;
对于TCP,我们绝不可能启动捆绑相同IP地址和相同端口号的多个服务器。
《UNIX Network ProgrammingVolume 1, Third Edition: TheSockets Networking API》}

我要回帖

更多关于 被装mfsocket怎么卸载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信