您的位置:首页 > 理论基础 > 计算机网络

网络编程常见问题

2011-01-30 11:27 246 查看
一、socket流程

socket 是面向客户/服务器模型而设计的,

针对客户和服务器程序提供不同的socket 系统调用

二、长连接和短连接

长连接:在多次请求中保持连接,使用同一个连接处理多次请求,直至出现错误或者异常才断开,并重新建立新的连接。

一般通过服务器端的长时间的读超时和客户端重用连接来实现。

典型例子:ui->as  as->bs

短连接:每个请求建立一个连接,请求处理完成,则断开连接。

一般服务器端使用短的读超时。

典型例子:browser->apache  client->LDC

ependingpoll同时支持长连接和短链接

三、常见问题

1.socket不够

大压力短连接,出现大量close_wait

解决方法:

lg.l_onoff = 1;

lg.l_linger = 0;

setsockopt(svrsock->sock, SOL_SOCKET, SO_LINGER,  (const char*)&lg, sizeof(lg));

2.长连接请求混乱

长连接请求错乱,收到其他线程的请求

导致原因:在长连接出错的情况下,并没有关闭连接

3.SIGPIPE信号

向断开(半关闭)的连接中write数据时产生

通常处理方式:

signal(SIGPIPE, SIG_IGN);

SIGPIPE信号被忽略 

4.TCP_NODELAY

TCP_NODELAY 不使用Nagle算法,不会将小包进行拼接成大包再进行发送,直接将小包发送出去,会使得小包时候用户体验非常好。

如果没有TCP_NODELAY在压力的情况下,会有延时(40ms)

Ependingpool自己默认的accept函数没有将socket设置成TCP_NODELAY.需要自己写回调函数来控制。

加入如下语句

client = ul_accept(sock, (struct sockaddr *)&sin, &slen);

       if (client > 0)     

               setsockopt(client, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));       

5.SO_REUSEADDR

通常用于服务监听套接字,支持服务快速重启

如:

// 地址复用

int on = 1;

setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));     

6.一次读写不完全

正常情况下,read和write可能读写比指定数量少的数据

原因可能是:

内核缓冲区满

被信号中断

解决方法:

反复调用直到数据被全部读(写)完(注意死循环)

7.网络字节序转换

big-endian和little-endian

相关函数:

htonl、htons、ntohl、ntohs

保证程序兼容性和可移植性

8.select中的bug  

不能操作多于1024个的socket

FD_SETSIZE在内核中定义为1024,并使用其声明最大的描述字集大小

解决方法:

调整程序,使其所需socket少于1024

使用poll()来代替select()

9.带超时的select

将要读的套接字加入rset中

调用select()。如果返回0则超时,返回-1则出错,否则利用FD_ISSET宏检查rset中的该套接字是否置位,如果是,则该套接字有数据可读,调用read()来读取

写超时控制和读超时控制的操作类似,但设置的是wret

10.带超时的Connect

设置套接字为非阻塞:

flags=fcntl(sockfd,F_GETFL,0);

fcntl(sockfd,F_SETFL,flags|O_NONBLOCK);

调用connect()。如果返回成功则连接已经建立。不成功则检查errno,如果errno为EINPROGRESS,表示连接正在试图建立中。其他错误则应返回出错。

将套接字加入rset和wset,调用select()。返回0则表示超时。

如果select()返回成功,则检查sockfd的状态,仅可写则为连接建立成功,可读且可写表示出错。

恢复套接字的原有状态:

fcntl(sockfd,F_SETFL,flags);

11.调用被信号中断

大多数的阻塞系统调用都可能被信号中断

read()、write()、accept()、select()、connect()……

恢复被中断的系统调用

设置信号标志为SA_RESTART(并不是所有系统都支持;并不是所有系统调用都支持)

判断errno为EINTR,则再次调用函数(推荐)

read()、write()、select()、accept()可以重新调用一次:

do {

     result = read(sockfd,buf,len);

}while ((result == -1) && (errno == EINTR));

connect()被中断不能重新调用,只能使用select()来等待连接完成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息