美文网首页
2018-07-21tcp

2018-07-21tcp

作者: 楚糖的糖 | 来源:发表于2018-08-16 22:11 被阅读0次

    udp通信模型中,在通信开始之前,不需要建立相关的链接,只需要发送数据即可

    tcp通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,"打电话""


    总结:

    tcp传输控制协议:稳定、相对于udp而言,要慢一些、web服务器都是使用的tcp

    udp用户数据包协议:不稳定、适当比tcp要快一些。

    想要完成一个tcp服务器的功能,需要的流程如下:

    socket:创建一个套接字,默认是主动的套接字(相当于买个手机)

    bind:绑定ip和port  (插上手机卡)

    listen:使套接字变为可以被动链接  (设计手机为正常接听状态(即能够响铃))                  listen(5)代表:最多可以接受5个客户端的连接

    accept:等待客户端的链接  (静静的等着别人拨打)

    recv/send:接收发送数据

    NAT模式下收发数据:

    #coding =utf-8

    from socket import *

    tcpSerSocket = socket(AF_INET,SOCK_STREAM)

    tcpSerSocket.bind(("",7788))

    tcpSerSocket.listen(5)

    newSocket,clientAddr=tcpSerSocket.accept()

    recvData=newSocket.recv(1024)

    print("接收到的数据是:%s"%recvData)

    newSocket.send(b"xiexie!")

    newSocket.close()

    tcpSerSocket.close()

    实现客户端收发功能:

    #coding=utf-8

    from socket import *

    tcpCliSocket =socket(AF_INET,SOCK_STREAM)

    serAddr=('192.168.20.125',7788)

    tcpCliSocket.connect(serAddr)

    sendData = raw_input("请输入要发送的数据")

    tcoCliSocket.send(sendData)

    recvData = tcpCliSocket.recv(1024)

    print("接收到的数据是%s"%recvData)

    tcpCliSocket.close()

    注意:对于套接字,服务器端有两个,客户端有一个。

    注意:参数类型是一个元组的。

    运行的时候先启动服务器端,再运行脚本文件:

    应用:模拟QQ聊天

    客户端参考代码:

    from socket import *

    tcpCliSocket=socket(AF_INET,SOCK_STREAM)

    serAddr = ("192.168.242.133",7788)

    tcpCliSocket.connect(serAddr)

    while True:

            sendData = input("send")

            if len(sendData)>0:

                    tcpCliSocket.send(sendData.encode("gb2312"))

            else:

                    break

            recvData = tcpCliSocket.recv(1024)

            print('recv:',recvData.decode("gb2312"))

    tcpCliSocket.close()

    服务端参考代码

    from socket import *

    tcpSerSocket=socket(AF_INET,SOCK_STREAM)

    tcpSerSocket.bind("192.168.242.133",7788)

    tcpSerSocket.listen(5)

    while True:

            newSocket,seraddr=tcpSerSocket.accept()

            while True:

                    recvdata =newSocket.recv(1024)

                    if len(recvData)>0:

                            print("recv",recvData.decode("gb2312"))

                    else:

                            break

                sendData = input("send:")

                newSocket.send(sendData.encode("gb2312"))

        newSocket.close()

    tcpSerSocket.close()

    listen参数问题

    from socket import *

    tcpSerSocket=socket(AF_INET,SOCK_STREAM)

    tcpSerSocket.bind("192.168.242.133",7788)

    tcpSerSocket.listen(int(input("请输入最大链接数')))

    while True:

            newSocket,cliAddr=tcpSerSocket.accept()

            print(cliAddr)

            sleep(1)

    客户端的代码:

    from socket import *

    for i in range(int(input("请输入最大的链接数")))

            s=socket(AF_INET,SOCK_STREAM)

            s.connect(("192.168.2420133",7788))

            print(i)

    mac系统就是写几就是几,而linux系统它自己有最大值,你写的不管用,这就是为什么linux系统合适做web服务器开发。

    在此期间,如果20个客户端调用了connect链接服务器,那么这个服务器的linux底层会自动维护2个队列(半链接和已链接)其中半链接和已链接的总数为listen中的值,如果这个值为5,那么意味着此时最多有5个客户端能够链接成功,而剩余的15个客户端阻塞在connect函数。

    如果服务器调用了accept,那么linux底层中的那个半链接和已连接中的客户端的个数就少了一个,因此此时那15个因为connect堵塞的客户端又会在进行链接来争抢这一个空出来的位置。


    多进程服务器

    from socket import *

    from multiprocessing import Process

    from time import sleep

    def dd(newSocket,destAddr):

            while True:

                    recvData = newSocket.recv(1024)

                    if len(recvData)>0:

                            print("recv[%s]:%s"%(str(destAddr),recvData))

                    else:

                            print("[%s]客户端已经关闭"%str(destAddr))

                            newSocker.close()

    def main():

    serSocket=socket(AF_INET,SOCK_STREAM)

    serSocket.setSockopt(SOL_SOCKET,SO_REUSEADDR,1)

    serSocket.bind(('192.168.242.133',7788))

    serSocket.listen(5)

    try:

            while True:

                    print("---主进程,等待")

                    newSocket,destAddr = serSocket.accept()

                    print("主进程,创建进程")

                    client = Process(target=dd,args=(newSocket,destAddr))

                    client.start()

                    newSocket.close()

    finally:

            serSocket.close()

    if __name__='__main__':

            main()

           默认情况下,两个独立的套接字不可与同一本地接口(在TCP/IP情况下,则是端口)绑定在一起。但是少数情况下,还是需要使用这种方式,来实现对一个地址的重复使用。设置了这个套接字,服务器便可在重新启动之后,在相同的本地接口以端口上进行监听。

            一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。     SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,允许重复绑定使用。server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项。

    通过为每个客户端创建一个进程的方式,能够同时为多个客户端进行服务,当客户端不是特别多的时候,这种方式还行,如果有几百上千个,就不可取了,因为每次创建进程等过程需要好较大的资源。


    多线程服务器

    from socket import *

    from threading import Thread

    from time import sleep

    def dd(newSocket,destAddr):

            while True:

                    recvData = newSocket.recv(1024)

                    if len(recvData)>0:

                            print("recv[%s]:%s"%(str(destAddr),recvData))

                    else:

                            print("[%s]客户端已经关闭"%str(destAddr))

                            break

          newSocker.close()

    def main():

    serSocket=socket(AF_INET,SOCK_STREAM)

    serSocket.setSockopt(SOL_SOCKET,SO_REUSEADDR,1)

    serSocket.bind(('192.168.242.133',7788))

    serSocket.listen(5)

    try:

            while True:

                    print("---主进程,等待")

                    newSocket,destAddr = serSocket.accept()

                    print("主进程,创建进程")

                    client = Thread(target=dd,args=(newSocket,destAddr))

                    client.start()

                    newSocket.close()

    finally:

            serSocket.close()

    if __name__='__main__':

            main()

    对于效率这一块,差不多的,但是进程耗费的资源要大,线程耗费的资源要小。不管是多进程还是多线程代码几乎一样,

    区别在于:在多线程中newSocket.close()不能关闭,因为线程是共享同一份资源的,也就是共享全局变量的,传递东西也就是传递的引用,一个进程里面所有的线程都有共用同一份东西的。

    如果serSocket不小心被close了,那么意味着:不能再接收新的客户端的链接了。

    如果newSocket被close了,那么意味着:这个套接字就不能再使用recv和send来收发数据了。

    相关文章

      网友评论

          本文标题:2018-07-21tcp

          本文链接:https://www.haomeiwen.com/subject/uwzobftx.html