socket编程的几个问题

网络编程离不开socket,接触不多时总觉得简单,无非是bind();listen();accept();send();recv()几个函数痴痴用上,能跑就不管三七二十一了。最近需要写个http代理,遇上几个问题。

socket的本质

从前认死理,怎么就recv()收到网络报文,功能还这么强大,嗅探,代理,服务器都用上它,就差没往硬件上想,现在想来也算是和自己和解了,在我的理解,socket是从传输层提取出的一套程序接口,供应用层使用,使我们不必面对实际的tcp/ip复杂的传输过程。它是一套规则和机制,灵感来源于Unix一切皆文件的设计,socket就像一个文件夹,创建,读取,写出,关闭,只不过这里对应的是网络数据。

socket中的accept()

accept()函数返回值是客户端socket和客户端地址信息,它创建了一个新的socket,称它为cli_socket,而原先绑定的socket称为soc。这里使我疑惑的地方就在于为什么同一个端口下有两个socket的存在。不是一个端口标识唯一的socket吗?
事实上,不是一个端口唯一标识,而是五元组标识一个socket,(source ip, source port, destination ip, destination port, protocol),而本地绑定的socket并不算一个完整的socket,它只包含三元组,即(destination ip, destination port, protocol),而accept()函数接受了来自客户端的信息,至此完成一个完整的socket链接,这个cli_socket用于接收和发送数据,而soc则继续用于监听客户端的connect请求。
再说明一点,虽说五元组唯一标识一个socket,并不是说这个端口就只能给一个socket使用,若是五元组中有不同的元素,比如说客户端ip和端口不同,那就是另一个socket,它和服务器端相同的端口和ip构成了新的五元组,比如说服务器端的80端口供多个客户端使用。
总的来说这些都是前人留下的规定,有的也不见得多明智,但目前还是主流,所以还是有必要知道。
参考1
参考2

socket中的数据接收问题

因为写的是一个代理,所以既要当客户端也要当服务端,在充当客户端过程中,需要和web服务器通信,很简单的一个建立连接,接收数据,是这样的:

SerSock = socket(AF_INET, SOCK_STREAM)
SerSock.connect(SerAddr)
SerSock.send(CMessage)
message = SerSock.recv(4096)
SerSock.close()

就是创建,连接,发送,接收,关闭的过程,但是报错,broken pipe。说是服务端还没传完数据,客户端就关闭了连接。
将接收到的数据输出了一下,发现数据都没传完,是这种:

Screenshot from 2017-07-12 22-10-34.png

细想,才知服务器传送数据并不是一次性传完的,学过计算机网络的都知道,传输层会将数据进行分片传输,选择不同的路径传送过来再组织到一起。那么分片的大小是多大呢?每个以太网帧都有最小的大小64bytes最大不能超过1518bytes,参考

将代码一改:

    SerSock = socket(AF_INET, SOCK_STREAM)
    SerSock.connect(SerAddr)
    SerSock.send(CMessage)
    FromSMessage = ''
    while True:
        message = SerSock.recv(4096)
        if not message:
            break
        FromSMessage += message
        SerSock.close()

可顺利运行。

socket中的非阻塞问题

代理程序虽然能运行,但访问一多就会崩掉。这里需要知道的是,socket中的send(),recv()函数都是阻塞函数,也就是说若数据没有发送完毕或者没有接收完毕,函数是不会返回的,那么随着accept的客户端请求多了,内存占用溢出,就会崩掉。怎样设计一个非阻塞的socket程序呢?
这里主要讲一下select这个对象,利用select对象的select()函数可以实现非阻塞,简单看一下:

select.select(rlist, wlist, xlist[, timeout])

select()的参数为3个列表:第一列表为读取输入数据的对象;第2个接收要发送的数据,第3个存放errors,加上一个超时设置。
返回值有三个:readable,writable,exceptional
readable有3种可能:对于用来侦听连接主服务器socket,表示已准备好接受一个到来的连接;对于已经建立并发送数据的链接,表示有数据到来;如果没数据到来,表示链接已经关闭。
writable的情况:连接队列中有数据,发送下一条消息。如果队列中无数据,则从output队列中删除。
socket有错误,也要从output队列中删除。
所以这里实现非阻塞大体流程就是,select函数轮循,看有那个socket队列有需要读或写的数据,有就全部接收或发送,没有就忙别的。代码大体如下:

def nonblocking(self):
        inputs=[self.client,self.target]
        while True:
            readable,writeable,errs=select.select(inputs,[],inputs,3)
            if errs:
                break
            for soc in readable:
                data=soc.recv(self.BUFSIZE)
                if data:
                    if soc is self.client:
                        self.target.send(data)
                    elif soc is self.target:
                        self.client.send(data)
                else:
                    break
        self.client.close()
        self.target.close()

参考1
参考2

至此,socket问题肯定不止于此,经事尚少,暂且留意了这些,做个总结,也希望能对他人有所帮助,不对之处还望指正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容