浅析TCP连接过程中server异常情况处理
2017-04-24 23:59
639 查看
#浅析TCP连接过程中server异常处理
基础环境:腾讯云ubuntu虚拟机
前置基础:对TCP连接有一个基本认识,能写进行简单socket编程
先简单介绍一下TCP编程流程
绑定套接字bind;
设置套接字为监听模式,进入被动接受连接状态listen;
接受请求,建立连接accpet;
读写数据read/write;
终止连接close。
与远程服务器建立连接connect;
读写数据read/write;
终止连接close。
server是Listen、Accept、Read/Write;client是Dial、Read/Write
client的Dial即包含了自动创建一个socket并connect的操作)
这是一个很简单的hello world程序,server监听本地10000端口,client连接本地10000端口,然后发送hello world消息,并结束进程。
client稍作修改
串口输出,在client连接好之后关闭server,这时候发现它你的消息发不出去,且会给你返回broken pipe的错误
那么再来看收,在连接建立好之后,server退出,client这边会收到什么呢?
修改下client
串口输出,在client连接好之后关闭server
可以看到收到的消息是空,收到的消息长度为0,且收到EOF连接断开的错误
服务器关机,这里一般是指正常关机,系统会向各个进程发送SIGTERM和SIGKILL信号,server进程会退出,然后关闭相应文件描述符,给对应client发送FIN消息。
启动server,打开client,关闭server,打开server
server侧打印
client侧打印
可以简单得出两点:
在服务器进程重启的情况下如果客户在主机崩溃重启前不主动发送数据,那么客户是不会知道服务器已崩溃。
在服务器退出后,就算重启,不进行设置直接使用原有套接字发送消息是无法发送成功的。
如果客户对服务器的崩溃情况很关心,即使客户不主动发送数据也这样,这需要进行相关设置(如设置套接口选项SO_KEEPALIVE或要依赖于某些客户/服务器心跳函数)。
http://blog.csdn.net/qq_15437667/article/details/51042366
基础环境:腾讯云ubuntu虚拟机
前置基础:对TCP连接有一个基本认识,能写进行简单socket编程
先简单介绍一下TCP编程流程
TCP简易编程流程
1.TCP服务器端编程流程如下:
创建套接字socket;绑定套接字bind;
设置套接字为监听模式,进入被动接受连接状态listen;
接受请求,建立连接accpet;
读写数据read/write;
终止连接close。
2.TCP客户端编程流程如下:
创建套接字socket;与远程服务器建立连接connect;
读写数据read/write;
终止连接close。
使用GO的示例代码
这个是最简单的server client模式:server是Listen、Accept、Read/Write;client是Dial、Read/Write
client的Dial即包含了自动创建一个socket并connect的操作)
package main import ( "fmt" "net" "os" ) func checkError(err error){ if err != nil { fmt.Println("Error: %s", err.Error()) os.Exit(1) } } func recvConnMsg(conn net.Conn) { // var buf [50]byte buf := make([]byte, 50) defer conn.Close() for { n, err := conn.Read(buf) if err != nil { fmt.Println("conn closed") return } //fmt.Println("recv msg:", buf[0:n]) fmt.Println("recv msg:", string(buf[0:n])) } } func main() { listen_sock, err := net.Listen("tcp", "localhost:10000") checkError(err) defer listen_sock.Close() for { new_conn, err := listen_sock.Accept() if err != nil { continue } go recvConnMsg(new_conn) } }
package main import ( "fmt" "net" "os" ) func checkError(err error){ if err != nil { fmt.Println("Error: %s", err.Error()) os.Exit(1) } } func main() { conn, err := net.Dial("tcp", "127.0.0.1:10000") checkError(err) defer conn.Close() conn.Write([]byte("Hello world!")) fmt.Println("send msg") }
这是一个很简单的hello world程序,server监听本地10000端口,client连接本地10000端口,然后发送hello world消息,并结束进程。
server异常场景
TCPserver主要有三种异常场景,分别为服务器主机崩溃、服务器主机崩溃后重启、服务器主机关机。1.服务器进程退出/服务器主机关机/
服务器进程退出,会关闭对应文件描述符,向连接上的客户端发送FIN消息,通知其关闭连接。且此时消息无法发送出去。client稍作修改
package main import ( "fmt" "net" "os" "time" ) func checkError(err error){ if err != nil { fmt.Println("Error: %s", err.Error()) os.Exit(1) } } func main() { conn, err := net.Dial("tcp", "127.0.0.1:10000") checkError(err) defer conn.Close() for { time.Sleep(1000 * time.Millisecond) ret, err := conn.Write([]byte("Hello world!")) fmt.Println("send msg len is %d", ret) if err != nil { fmt.Println(err) } } }
串口输出,在client连接好之后关闭server,这时候发现它你的消息发不出去,且会给你返回broken pipe的错误
feiqianyousadeMacBook-Pro:go yousa$ go run client.go send msg len is %d 12 send msg len is %d 12 send msg len is %d 12 send msg len is %d 12 send msg len is %d 12 send msg len is %d 12 send msg len is %d 0 write tcp 127.0.0.1:52732->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52732->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52732->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52732->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52732->127.0.0.1:10000: write: broken pipe send msg len is %d 0
那么再来看收,在连接建立好之后,server退出,client这边会收到什么呢?
修改下client
package main import ( "fmt" "net" "os" ) func checkError(err error){ if err != nil { fmt.Println("Error: %s", err.Error()) os.Exit(1) } } func main() { conn, err := net.Dial("tcp", "127.0.0.1:10000") buf := make([]byte, 50) checkError(err) defer conn.Close() /*time.Sleep(1000 * time.Millisecond) ret, err := conn.Write([]byte("Hello world!")) */ n, err := conn.Read(buf) fmt.Println("recv msg is %s\n recv msg len is %d", buf, n) if err != nil { fmt.Println(err) } }
串口输出,在client连接好之后关闭server
feiqianyousadeMacBook-Pro:go yousa$ go run client.go recv msg is %s recv msg len is %d [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 0 EOF
可以看到收到的消息是空,收到的消息长度为0,且收到EOF连接断开的错误
服务器关机,这里一般是指正常关机,系统会向各个进程发送SIGTERM和SIGKILL信号,server进程会退出,然后关闭相应文件描述符,给对应client发送FIN消息。
2.服务器进程退出后重启/服务器主机崩溃后重启
依然使用上述的测试进程。启动server,打开client,关闭server,打开server
server侧打印
feiqianyousadeMacBook-Pro:go yousa$ ./server recv msg: Hello world! recv msg: Hello world! recv msg: Hello world! ^C #重启server feiqianyousadeMacBook-Pro:go yousa$ ./server
client侧打印
feiqianyousadeMacBook-Pro:go yousa$ go run client.go send msg len is %d 12 send msg len is %d 12 send msg len is %d 12 send msg len is %d 12 #server进行重启 send msg len is %d 0 write tcp 127.0.0.1:52934->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52934->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52934->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52934->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52934->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52934->127.0.0.1:10000: write: broken pipe send msg len is %d 0 write tcp 127.0.0.1:52934->127.0.0.1:10000: write: broken pipe ^Csignal: interrupt feiqianyousadeMacBook-Pro:go yousa$
可以简单得出两点:
在服务器进程重启的情况下如果客户在主机崩溃重启前不主动发送数据,那么客户是不会知道服务器已崩溃。
在服务器退出后,就算重启,不进行设置直接使用原有套接字发送消息是无法发送成功的。
如果客户对服务器的崩溃情况很关心,即使客户不主动发送数据也这样,这需要进行相关设置(如设置套接口选项SO_KEEPALIVE或要依赖于某些客户/服务器心跳函数)。
3.服务进程崩溃
此时客户端发出数据后,会一直阻塞在套接字的读取响应。但是由于服务器主机已崩溃,TCP客户端会持续重传数据分节,试图从服务器接收一个ACK[一般重传12次(源自Berkeley的实现)]后,客户TCP最终选择放弃,返回给应用经常一个ETIMEDOUT错误;或者是因为中间路由器判定服务器主机不可达,则返回一个目的地不可达的ICMP消息响应,其错误代码为EHOSTUNREACH或ENETUNREACH。参考
简单代码参考go tcp server-clienthttp://blog.csdn.net/qq_15437667/article/details/51042366
相关文章推荐
- TCP连接中的异常断开情况处理
- TCP连接中的异常断开情况处理
- 关于TCP连接极端异常情况的处理方法的思考
- TCP/IP详解--TCP中异常关闭连接的意义 异常关闭的情况
- TCP/IP详解--TCP中异常关闭连接的意义 异常关闭的情况
- 浅析Java程序异常处理的特殊情况
- TCP连接断开情况处理
- lftp连接异常情况分析过程(lftp与sftp结合使用)
- lftp连接异常情况分析过程
- TCP建立连接结束过程,client与server数据传输
- 唯快不破:TCP/IP详解--TCP中异常关闭连接的意义 异常关闭的情况
- Tomcat+MySQL应用中连接超时造成各种异常情况的处理
- TCP建立/关闭连接时握手过程中的状态情况
- lftp连接异常情况分析过程
- Android adb连接异常情况处理
- Redis源码系列28:ServerSocket接收到client的连接请求处理过程
- 关于vfp调用连接服务器(linkServer)异常的处理方法
- 实例解说TCP连接建立及结束过程详解
- 几个在MS SQL Server处理IP的函数/存储过程
- Oracle SQL Developer连接MS SQL SERVER 2000的处理