liunx网络编程(1) 使用select 改造现有代码
2013-12-04 20:38
281 查看
(1)分析client代码执行
功能:发出请求 发送和读取字符串 然后关闭连接
查看网络状态
结论:
1 client和server 建立了连接 tcp:ESTABLISHED
但是为什么client 一直在阻塞recv()数据
应该执行完毕 马上退出
代码:
Tcpdump跟踪
sudo tcpdump -i 5 "tcp and port 12345"
分析:
length 0 的行是tcp的确认信息 保证可靠连接 每次才做都进行确认 底层对外不可见
行数:
1
client(46282) 发出concet 请求 【Flags [S]】 * S : SYN - 同步; 表示开始会话请求 请求 seq =2489333847
2
server(12345) ack =seq+1= 2489333848 进行确认(tcp是可靠的传输)表明你发出的请求确认了
然后发出可以连接的请求seq
3
client(46282) --确认 Flags [.] (tcp是可靠的传输)
············································3次握手完毕 开始建立了连接----------------------------------------
4 Client--->server
Flags [P.], 表示开会传递数据
5 Server-client 确认。
没有退出Flags [R.],
然后gdb服务端在做什么
结论:
服务端功停留在输入一个 getchar()
查看代码
输入 a
客户端输出:
Tcpdump:
sudo tcpdump -i 5 "tcp and port 12345"
03:51:55.506292 IP localhost.46283 > localhost.12345: Flags [R.], seq 23, ack 49, win 513, options [nop,nop,TS val 35611448 ecr 35610261], length 0
Client 发出 close 请求 程序退出 [ R : RST - 复位;中断一个连接 ]
---------------------- 优化建议 ----------------------------------------------------------------
Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如
connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等
待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。
可是使用Select就可以完成非阻塞
补充tcp基础知识
* F : FIN - 结束; 结束会话
* S : SYN - 同步; 表示开始会话请求
* R : RST - 复位;中断一个连接
* P : PUSH - 推送; 数据包立即发送
* A : ACK - 应答
* U : URG - 紧急
* E : ECE - 显式拥塞提醒回应
* W : CWR - 拥塞窗口减少
参考
《TCP/IP详解 卷一》
后续带补充 第二章节
功能:发出请求 发送和读取字符串 然后关闭连接
Gdb调试client: wang@ubuntu:~/study/code$ gdb -p 9008 (gdb) bt #0 0x00a78422 in __kernel_vsyscall () #1 0x00ec5681 in recv () from /lib/tls/i686/cmov/libc.so.6 #2 0x08048b1a in main (argc=1, argv=0xbfe85e04) at client.cpp:73 (gdb)
查看网络状态
wang@ubuntu:~$ netstat -an |grep 12345 tcp 0 0 0.0.0.0:12345 0.0.0.0:* LISTEN tcp 22 0 127.0.0.1:12345 127.0.0.1:46285 ESTABLISHED tcp 0 0 127.0.0.1:46285 127.0.0.1:12345 ESTABLISHED
结论:
1 client和server 建立了连接 tcp:ESTABLISHED
但是为什么client 一直在阻塞recv()数据
应该执行完毕 马上退出
代码:
memset(send_buf,0,sizeof(send_buf)); sprintf(send_buf,"client client client \n"); if (send(client_socket,send_buf,strlen(send_buf),0) == -1) { printf("send error/n"); close(client_socket); return -1; } // 阻塞在 recv中 直到 server 发出信息 tcp:ESTABLISHED recvBytes=recv(client_socket,recv_buf,strlen(recv_buf),0); if(recvBytes >0) { printf("server::: %s \n", recv_buf);//接收数据包正常,数据包中的数据大于0个字节 }else if(recvBytes == 0 ) { printf("client: %s \n", recv_buf); memset(recv_buf,0,sizeof(recv_buf)); //close(client_socket);//传输数据包操作完成,连接断开 break; }else if(recvBytes <0) { close(client_socket); perror("recv error"); return -1; }
Tcpdump跟踪
sudo tcpdump -i 5 "tcp and port 12345"
09:19:57.059094 IP localhost.46282 > localhost.12345: Flags [S], seq 2489333847, win 32792, options [mss 16396,sackOK,TS val 32534158 ecr 0,nop,wscale 6], length 0 09:19:57.059116 IP localhost.12345 > localhost.46282: Flags [S.], seq 86594463, ack 2489333848, win 32768, options [mss 16396,sackOK,TS val 32534158 ecr 32534158,nop,wscale 6], length 0 09:19:57.059189 IP localhost.46282 > localhost.12345: Flags [.], ack 1, win 513, options [nop,nop,TS val 32534158 ecr 32534158], length 0 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 09:19:57.059712 IP localhost.12345 > localhost.46282: Flags [P.], seq 1:25, ack 1, win 512, options [nop,nop,TS val 32534158 ecr 32534158],length 24 09:19:57.059778 IP localhost.46282 > localhost.12345: Flags [.], ack 25, win 513, options [nop,nop,TS val 32534158 ecr 32534158], length 0
分析:
length 0 的行是tcp的确认信息 保证可靠连接 每次才做都进行确认 底层对外不可见
行数:
1
client(46282) 发出concet 请求 【Flags [S]】 * S : SYN - 同步; 表示开始会话请求 请求 seq =2489333847
2
server(12345) ack =seq+1= 2489333848 进行确认(tcp是可靠的传输)表明你发出的请求确认了
然后发出可以连接的请求seq
3
client(46282) --确认 Flags [.] (tcp是可靠的传输)
············································3次握手完毕 开始建立了连接----------------------------------------
4 Client--->server
Flags [P.], 表示开会传递数据
5 Server-client 确认。
没有退出Flags [R.],
然后gdb服务端在做什么
(gdb) bt #0 0x00886422 in __kernel_vsyscall () #1 0x002b07b3 in read () from /lib/tls/i686/cmov/libc.so.6 #2 0x002571db in _IO_file_underflow () from /lib/tls/i686/cmov/libc.so.6 #3 0x00258a7b in _IO_default_uflow () from /lib/tls/i686/cmov/libc.so.6 #4 0x00259ea8 in __uflow () from /lib/tls/i686/cmov/libc.so.6 #5 0x0024f91c in getchar () from /lib/tls/i686/cmov/libc.so.6 #6 0x08048d6f in main (arg=1, argv=0xbf9e5164) at server.cpp:127 (gdb)
结论:
服务端功停留在输入一个 getchar()
查看代码
if(getchar() == -1) { close(serverSock);//停止server break; } printf("server send begin....\n"); //发送客户端的信息 if (send(clientSock,send_buf,strlen(send_buf),0) == -1)
输入 a
客户端输出:
Tcpdump:
sudo tcpdump -i 5 "tcp and port 12345"
03:51:55.506292 IP localhost.46283 > localhost.12345: Flags [R.], seq 23, ack 49, win 513, options [nop,nop,TS val 35611448 ecr 35610261], length 0
Client 发出 close 请求 程序退出 [ R : RST - 复位;中断一个连接 ]
---------------------- 优化建议 ----------------------------------------------------------------
Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如
connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等
待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。
可是使用Select就可以完成非阻塞
在client中添加 select 出来 FD_ZERO(&fdsr);//清除描述符集 FD_SET(serverSock, &fdsr);//把sock_fd加入描述符集 ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv); if (ret < 0) { ////没有找到有效的连接 失败 perror("select"); break; }else if (ret == 0) { /// 指定的时间到 连接进来 //printf("timeout\n"); continue; }
补充tcp基础知识
TCP FLAG 标记
基于标记的TCP包匹配经常被用于过滤试图打开新连接的TCP数据包。TCP标记和他们的意义如下所列:* F : FIN - 结束; 结束会话
* S : SYN - 同步; 表示开始会话请求
* R : RST - 复位;中断一个连接
* P : PUSH - 推送; 数据包立即发送
* A : ACK - 应答
* U : URG - 紧急
* E : ECE - 显式拥塞提醒回应
* W : CWR - 拥塞窗口减少
参考
《TCP/IP详解 卷一》
后续带补充 第二章节
相关文章推荐
- 03_MyBatis基本查询,mapper文件的定义,测试代码的编写,resultMap配置返回值,sql片段配置,select标签标签中的内容介绍,配置使用二级缓存,使用别名的数据类型,条件查询ma
- 03_MyBatis基本查询,mapper文件的定义,测试代码的编写,resultMap配置返回值,sql片段配置,select标签标签中的内容介绍,配置使用二级缓存,使用别名的数据类型,条件查询ma
- 使用 SOAP Toolkit 2.0 将现有代码作为 Web 服务提供
- 使用js对select动态添加和删除OPTION示例代码
- 设计模式(1)-单例模式 及使用该模式改造的日志写入代码
- 【C#】解决ListView,在代码部分使用Select=true选定时的背景问题
- libevent for qt网络模块,直接替换qt的select模型,支持epoll,select,pool.使用非常简单,无需修改以前的代码结构
- 1 开发一个注重性能的JDBC应用程序不是一件容易的事. 当你的代码运行很慢的时候JDBC驱动程序并不会抛出异常告诉你。 本系列的性能提示将为改善JDBC应用程序的性能介绍一些基本的指导原则,这其中的原则已经被许多现有的JDBC应用程序编译运行并验证过。 这些指导原则包括: 正确的使用数据库MetaData方法 只获取需要的数据 选用最佳性能的功能 管理连
- 使用 Android NDK 重用现有的 C 代码
- 使用2000将现有代码作为Web服务提供
- C++使用Mysql的详细步骤及各个常用方法的代码演示:select,insert,update,delete
- 使用 .NET 框架将现有代码作为 Web 服务提供
- 使用js对select动态添加和删除OPTION示例代码
- 使用js对select动态添加和删除OPTION示例代码
- 使用div模拟默认select效果代码。
- 使用SQL Server 将现有代码作为Web 服务提供
- 将select改造成搜索框(chosen.jquery.js)使用