tcp/udp

'''
UDP(缺乏可靠性,可以是全双工) 效率高
缺点:
1.不保证数据包一定会到达目的地
2.不保证各个数据包先后顺序
3.不保证每个数据包只到达一次
UDP是无连接的
UDP不提供可靠性,UDP本身不提供确认,序列号,RTT估算,超时和重传等机制

TCP(是全双工的) 效率低
优点:(可靠)
1.客户与服务之间先建立连接,在跨该连接与那个服务器交换数据,最后终止这个连接。
2.当TCP向另一端发送数据,要求对端返回一个确认,没有收到确认,TCP就会自动重传数据并等待更长时间(多次失败后,断开连接)
3.TCP提供流量控制(server接受多大字节数)
'''
import socket
import os
import signal
import select
import queue

listened = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

listened.bind(('127.0.0.1', 8000))

listened.listen(5)

print('start server')


def str_echo(conn):
    while True:
        data = conn.recv(1024)
        if len(data) > 0:
            conn.send(data)
        if not data:
            print('read error')
            break


def sig_chid(a, b):
    while True:
        try:
            pid, status = os.waitpid(-1, os.WNOHANG)
            if status == 0:
                print('child process pid[%s][%s] is del' % (pid, status))
            return
        except:
            print('...')
            break


signal.signal(signal.SIGCHLD, sig_chid)

while True:
    try:
        connfd, addr = listened.accept()
        print(addr)
        if (os.fork() == 0):
            listened.close()
            str_echo(connfd)
            exit(0)

        connfd.close()
    except KeyboardInterrupt:
        listened.close()
        print('close server')
        break

#
# # yong lai chu li xiaoxi
# outputs = []
# # neihe jiance bingfa lianjie
# inputs = [listened]
# # cun fang client : MSG_QUEUE
# msg_dic = {}
#
# # select
# while True:d
#     reads, writes, execs = select.select(inputs, outputs, inputs)
#     print(reads, writes, execs)
#     # readable
#     for r in reads:
#         print('rrr', r)
#         if r is listened:
#             client, addr = r.accept()
#             print(client, addr)
#             inputs.append(client)
#             msg_dic[client] = queue.Queue()
#         else:
#             data = r.recv(1024)
#             print('data:', data)
#             if data:
#                 msg_dic[r].put(data)
#                 outputs.append(r)
#             else:
#                 #remove  client
#                 inputs.remove(r)
#                 del msg_dic[r]
#
#     for w in writes:
#         print('www', w)
#         data = msg_dic[w].get()
#         w.send(data)
#         #
#         outputs.remove(w)
server
import socket
import os
import signal

def create_a_client():
    sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sockfd.connect(('127.0.0.1', 8000))

    return sockfd


# version:1
def str_cli(sock):
    stdineof = 0
    while True:
        try:
            if stdineof:
                # jing li le EOF shoudong guanbi client
                print('close client nomal')
                exit(0)
            msg = input('>>>')
            sock.send(msg.encode('utf8'))
            recv_msg = sock.recv(1024)
            print(stdineof, recv_msg)
            if recv_msg:
                print('recieve msg : %s' % recv_msg)
            else:
                print('server is closed')
        except EOFError:
            # client close
            stdineof = 1
            sock.shutdown(socket.SHUT_WR)
            continue


# nomal
# sockfds = [create_a_client()]
# # create 5 clients
# # for i in range(5):
# #     sockfds.append(create_a_client())
#
# try:
#     str_cli(sockfds[0])
# except BrokenPipeError:
#     print('server is closed')
#     exit(0)


# selet solve
# 1.zhongzhi  input
# 2.piliang shuru wenti
import sys
import select
import queue

# readable
inputs = [create_a_client(), sys.stdin]
# writeable
outpus = []


# version:2
def select_str_cli(rl: list, sockfd: socket.socket):
    stdineof = 0
    while True:
        reads, writes, execs = select.select(rl, [], [])
        print(reads, writes)
        for r in reads:
            if r is sys.stdin:
                # biao zhun shu ru
                n = sys.stdin.readline()

                if n == '':
                    print('EOF signal')
                    # EOF
                    # shutdowm
                    stdineof = 1
                    sockfd.shutdown(socket.SHUT_WR)
                    continue
                else:
                    # stdin jiaru dao ke xie
                    sockfd.send(n.encode('utf8'))
            if r is sockfd:
                # sockfd shuju kedu
                # sock readable
                msg = r.recv(1024)
                if not msg:
                    if stdineof == 1:
                        return
                    else:
                        print('serve is preclosed')
                        return

                print('recv from server :%s' % msg)


# version:3
def fork_str_cli(sockfd:socket.socket):
    if os.fork() == 0:
        # son process
        while True:
            data = sockfd.recv(1024)
            if data:
                print()
                print('from server :::%s' % data)
            else:
                break

        os.kill(os.getpid(),signal.SIGTERM)
        exit(0)

    while True:
        try:
            msg = input('>>>')
            print('sys stdin :%s' % msg)
            sockfd.send(msg.encode('utf8'))
        except EOFError:
            print('EOF')
            break

    sockfd.shutdown(socket.SHUT_WR)#EOF FIN

    return

# fork_str_cli(inputs[0])
# select_str_cli(inputs, inputs[0])



exit(0)
client

 select  解决客户端主动接受  服务区FIN信号

以下特殊情况需要注意:

### TCP 客户端关闭,服务端关闭(参考Unix网络编程)



#### 1.tcp客户端正常关闭

```
当client主动发送完数据,主动键入EOF字符(*nix: Ctrl-D, Windows: Ctrl-Z+Return/Enter)

1.client进程exit(0) 会主动向server发送FIN,服务器TCP会主动回一个ACK,此时关闭了tcp连接终止的前半部分。此时,服务器SOCKET处于CLOSE_WAIT状态,客户端SOCKET处于FIN_WAIT2状态。

2.当服务器TCP接收到FIN时,服务器子进程阻塞与read调用,read调用返回0(即空字符串),此时返回服务器的子进程函数,服务器子进程调用exit终止。就是会触发TCP连接终止的后半部分,服务器TCP发送FIN到客户TCP,客户TCP回一个ACK给服务器TCP。至此客户端TCP处于TIME_WAIT状态。
```



#### 2.服务器进程终止

```
1.找到服务TCP对应的子进程kil,此时子进程所有打开的描述符都被关闭。导致服务TCP会向客户TCP发送FIN,客户TCP回一个ACK给服务TCP,此时服务TCP到客户TCP的连接终止。服务TCP处于FIN_WAIT2,客户TCP处于CLOSE_WAIT。

2.此时客户端阻塞在input,此时客户端是可以向服务端send的,但是由于服务端--》客户端的连接关闭,不能send,
于是服务器响应了一个RST给客户端,客户端recv到一个''数据。
        即客户并没有立即去 关闭到服务端的连接。
```

#### 3.服务器主机崩溃

#### 4.服务器主机崩溃后重启

#### 5.服务器主机关机
原文地址:https://www.cnblogs.com/liuer-mihou/p/13627907.html