一些基本问题:大小端,网络字节序,socket编程函数的注意点,gdb和coredump调试
1,什么是大小端?
大小端是指数据在内存的的存放顺序,现代计算机一次能够加载32bit或者64bit的数据或者指令,因而数据的存放顺序影响它被装载到整数的值。以小端来讲:低地址存数据的低位,高地址存数据的高;而大端敲好反过来:高地址存低位,地址存高位。
2.测试大小端
测试大小端最常用的方法是使用一个联合体,定义成员为一个short和char然后给short类型变量赋值为1,看char变量是否也是1,如果是说明是小端,反之是大端。
#include<iostream>
using namespacestd;
int main()
{
union et{
short a;
char b;
};
et t;
t.a=1;
if(t.b==1)
{
cout<<"小端"<<endl;
}
else
{
cout<<"大端"<<endl;
}
return 0;
}
3.网络字节序是大端的,因此当从主机字节序向网络字节序进行转换时需要根据本机的大小端进行转换,主机端是小端,则向网络发送数据时需要转化为大端,主机本身是大端的就不必进行转换了。再者介绍下面4个解决网络字节序和主机字节序转换问题的函数、
一二均为host to network long主机字节序long转换为网络字节序的long,第二个只不过是short之间的转换而已。第三个和第四个是针对于net to host网络字节序向主机字节序的转换(主机字节序是小端)
4,listen
看函数声明
Listen创建监听队列,将完成三次握手处于established状态的连接放入监听队列中,listen的第二个参数就backlog就是用于指定内核监听队列的最大长度。当然这个长度包含了处于半连接状态和完全连接状态的socket的上限。当然现在版本的backlog只是代表处于完全连接状态的socket的上限。处于半连接状态syn_rcvd的上限值可以通过/proc/sys/net/ipv4/tcp_max_syn_backlog内核参数定义,其典型值是5。
Listen成功返回0,失败返回-1,并设置errno.当然实际情况中处于完全连接状态的并在队列中的一般是backlog+1,不过这并不一定,但是实际处在完全连接上的socket要比backlog值要大
5.recv和send是专门面向tcp的read和write系统调用
它们都返回ssize_t有符号整数。Sockfd都是发送要接收或者发送的socket连接套接字,由accept返回得到,buf保存从接收缓冲区读取的数据或者是从要从buff的数据放入大发送缓存区,二者的len都用于指定数据量的大小。最后的flag是对数据的收发进行额外的控制作用。
表示数据链路层持续监听对方的回应,直到得到答复。它仅用于SOCK_DGRAM或者SOCK_RAW类型的socket
不查看路由表(don’t route),直接将数据发送给本地局域网络内的主机,这表示发送者确切直到目标主机就在本地网络上。
对于socket的本次操作是非阻塞的
告诉内核应用程序还有更多的数据要发送,内核将超时等待新数据写入TCP发送缓冲区后一并发送,这样可以防止TCP发送过多小的报文段,从而提高传输效率
往读端关闭的管道或者套接字连接中的写入数据时不引发SIGPIPE信号
发送或接受紧急数据
还有
MSG_PEEK窥视缓冲中的数据,此次读操作不会导致这些数据被清除
MSG_WAITALL 读取到指定字节数才返回
返回值方面:
Recv>0接收成功,返回实际接收的字节数;recv=-1接收失败并设置errno,等于0说明对方断开连接。
Send>0发送成功,返回实际发送的字节数,=-1代表失败,并设置errno
6time_wait状态
Time_wait状态存在的意义在于两点
1. 将前面发送的,未及时到达本端,但是现在到或者将来到的所有失效的数据包丢弃
2. 可靠的终止TCP连接:保证最后的fin以及对于fin的确定信息被发送和接收到,从而终止双方的TCP连接。
如何解决time_wait?
使用setsockopt系统调用
Level设置成SOL_SOCKET,optname设置成SO_REUSEADDR,reuse设置成intreuse=1;,&reuse,最后是前面一个参数的长度sizeof(int),经过setsockopt设置之后即使处于time_wait的socket绑定的地址也可以立即被复用,
方法二:修改内核参数/proc/sys/net/ipv4/tcp_tw_recycle来快速复用原来被绑定的socket地址。
7.accept调用
从listen监听队列中接收一个连接,但是它只负责从监听队列中读取连接,但是不关心连接处于何种状态。比如说在客户端和服务器断开连接之后,强行将这个连接中断,并在一会回复连接,会发现accept还是会正常返回,也就是说它对于网络环境的好坏义务所知,只是从队列里面去一取出一个连接并返回即可,对取出的连接套接字的状态是不关心的。
Sockfd是本端的套接字,addr用于存放被接收连接的远程sock的地址信息,该地址长度len,accept成功返回一个新的sockfd用于唯一标识被接受的这个连接,服务器可以通过读写该新的套接字与远程客户端进行通信。
Coredump调试
Coredump调试的原因:gdb调试效率较低时可以使用coredump内核转储文件进行调试。
首先编写一段带有segment falut的代码
远行发现报错
使用ulimit查看一下信息
将core file size设置成unlimited
再次编译并加入调试选项-g,并运行程序,得到结构段错误的同时还将核心转储了
使用gdb sg(被调试的可执行文件) core文件,得出详细的错误信息,非常之方便的就找到了错误出现的地方
最后通过设置ulimit的选项可以生成不同的文件进行调试,具体流程与coredump差不多。
gdb调试依赖于gcc在编译链接生成elf可执行文件的调试信息,产生调试信息,需要在gcc命令最后加上-g选项,如上面的gcc sg_fault.c –o sg –g
p var打印一个变量var的地址
bt查看堆栈调用情况
b n在第n行插入断点
s 进入一个函数或者过程
display var打印被跟踪的变量的值
n用于单步执行
l n显示从n行开始的代码
thread info多线程调试
thread id切换到线程id中去
常用就这些,再多就去手册查。。。。