码迷,mamicode.com
首页 > 其他好文 > 详细

socket编程

时间:2017-05-03 19:23:28      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:启用   处理   存在   close   基于   对象   win   溢出   阻塞   

一 客户端/服务器架构

c/s架构

server端要:

1、力求一直提供服务

2、要绑定一个唯一的地址,让客户端能明确找到

二 osi七层

数据链路层:以太网协议,进行数据分组,head部分包含mac地址,有了mac地址在子网内就可以以广播的方式通信

网络层:基于IP协议,arp协议

传输层:tcp、udp协议

三 socket层

技术分享

 

四 socket是什么

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序

而程序的pid是同一台机器上不同进程或者线程的标识

五 套接字发展史及分类

基于文件类型的套接字家族:套接字家族的名字:AF_UNIX

基于网络类型的套接字家族:套接字家族的名字:AF_INET

六 套接字工作流程

技术分享

 

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

七 基于TCP的套接字

tcp服务端

ss = socket() #创建服务器套接字
ss.bind()      #把地址绑定到套接字
ss.listen()      #监听链接
inf_loop:      #服务器无限循环
    cs = ss.accept() #接受客户端链接
    comm_loop:         #通讯循环
        cs.recv()/cs.send() #对话(接收与发送)
    cs.close()    #关闭客户端套接字
ss.close()        #关闭服务器套接字(可选)

tcp客户端

 cs = socket()    # 创建客户套接字
 cs.connect()    # 尝试连接服务器
 comm_loop:        # 通讯循环
     cs.send()/cs.recv()    # 对话(发送/接收)
 cs.close()            # 关闭客户套接字

 

socket通信流程与打电话流程类似,我们就以打电话为例来实现一个low版的套接字通信:

 

 

#服务端
import
socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#socket.AF_INET 基于网络的套接字,socket.SOCK_STREAM基于TCP协议的套接字  买手机 phone.bind((127.0.0.1,8080)) #绑定手机卡 phone.listen(5) #开机 ?5
conn,addr=phone.accept() #等待电话链接,连接的对象和客户端地址
print(‘电话线路是‘,conn)
print(‘客户端的手机号是‘,addr)
data=conn.recv(1024) #收消息  ?1024
conn.send(data.upper())
conn.close() #挂电话
phone.close() #手机关机
#客户端
import
socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect((127.0.0.1,8080))
data=phone.recv(1024)
print(data)
phone.close()

上述流程的问题是,服务端只能接受一次链接,然后就彻底关闭掉了,实际情况应该是,服务端不断接受链接,然后循环通信,通信完毕后只关闭链接,服务器能够继续接收下一次链接,下面是修改版:

#服务端
import
socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #在bind前加,重启释放地址 phone.bind((127.0.0.1,8080)) #绑定手机卡 phone.listen(5) #开机,在缓存中可以缓存5个连接请求 print(starting....) while True: #链接循环 conn,addr=phone.accept() #等待电话链接 print(电话线路是,conn) print(客户端的手机号是,addr) while True: #通信循环 try: #应对windows系统 data=conn.recv(1024) #收消息,最大一次接受1024个字节 #if not data:break #linux系统中,客户端断了链接会date接收空,服务端陷入循环 print(客户端发来的消息是,data) conn.send(data.upper()) except Exception: break conn.close() phone.close()
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect((127.0.0.1,8080))

while True: #通信循环
    msg=input(>>: ).strip()
    if not msg:continue
    phone.send(msg.encode(utf-8))
    data=phone.recv(1024)
    print(data)

phone.close()

问题:

有的同学在重启服务端时可能会遇到

技术分享

这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址(如果不懂,请深入研究1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发情况下会有大量的time_wait状态的优化方法)

解决方法:

技术分享
#加入一条socket配置,重用ip和端口

phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind((127.0.0.1,8080))
方法一
技术分享
发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决,
vi /etc/sysctl.conf

编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
 
然后执行 /sbin/sysctl -p 让参数生效。
 
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;

net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间
方法二

 

socket编程

标签:启用   处理   存在   close   基于   对象   win   溢出   阻塞   

原文地址:http://www.cnblogs.com/domestique/p/6803302.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!