www.cs.newpaltz.edu

Download Report

Transcript www.cs.newpaltz.edu

Chapter III
net_py
TCP

workhorse of the Internet – 1974
- data stream (mule train versus conveyor belt)

most traffic suited to TCP:
- long conversations like SSH, large exchanges like HTTP




Reliability: packet sequence numbers and retransmission.
TCP Sequence Number: byte number of first byte in data
package plus 1 for SYN and 1 for FIN
Retransmitted packets can begin at different packet
boundaries.
Initial SeqNum is randomly choosen to confound “villains”.
net_py
TCP is bursty


TCP noes not keep the sender and receiver in lock-step.
Sender can send multiple packets with no acknowledgment
of any being received.
net_py
TCP Example
sender
receiver
ACK 15
time
ACK 40
net_py
next expected
byte number is
15
TCP Window
sender
receiver
ACK 15
TCP Window:
Sender has sent 40
bytes with no ACK
received. So its
window is 40 bytes.
ACK 40
Actual Window size:
4096.
time
net_py
TCP Overwhelmed
sender
receiver
TCP Overwhelmed:
ACK 15
time
ACK 40
net_py
Receiver, if overwhelmed, sends TCP
option, telling sender
to shut window down;
specifies window new
window size.
TCP Congested
sender
receiver
TCP Congested:
ACK 15
time
ACK 40
net_py
Receiver, if it sees a
missing packet,
assumes congestion
and shuts the window
down as in the case of
being overwhelmed.
When to use TCP

Most of the time.

When is it inappropriate?
- single request/reply exchange – TCP uses 9 packets in total
- too many clients – each connection costs memory allocation,
port allocation, etc.
- real time like audio chat; retransmitted voice is discarded
because conversation has moved on.
normally compressed voice
highly compressed voice from previous and next packet
net_py
TCP Socket

Listen Sockets and Data Sockets.

Listen Sockets: like UDP, open and waiting for SYN

Data Sockets always involve a connection.
(localIP,localport,remoteIP, remoteport)


UDP socket.connect() shows intention of data exchange
between two particular processes and is optional
TCP socket.connect() does the same and is fundamental.
net_py
passive socket
client
in a loop
server
listen = socket.listen()
only accepts SYN
s_data = listen.accept()
and blocks
c_data = socket.connect()
c_data.send()
s_data.recv()
active sockets,
c_data and s_data are
identical in nature, identified by
(clntIP,clntPort,servIP,servPort)
ie a connection
NOTE: Hundreds or thousands of active sockets are possible on server with
same (srvIP,srvPort) pair but only one passive socket with the same pair.
net_py
Example:
#!/usr/bin/env python
# Foundations of Python Network Programming - Chapter 3 - tcp_sixteen.py
# Simple TCP client and server that send and receive 16 octets
import socket, sys
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# doesn't know yet if active or passive
HOST = sys.argv.pop() if len(sys.argv) == 3 else '127.0.0.1'
PORT = 1060
def recvall(sock, length): # used by both client and server
data = ''
while len(data) < length: # building a complete message
more = sock.recv(length - len(data))
if not more:
raise EOFError('socket closed %d bytes into a %d-byte message'
% (len(data), length))
data += more
return data
net_py
Example:
if sys.argv[1:] == ['server']:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT)) # bind to whatever we wish <HOST>
s.listen(1)
while True:
print 'Listening at', s.getsockname()
sc, sockname = s.accept()
print 'We have accepted a connection from', sockname
print 'Socket connects', sc.getsockname(), 'and', sc.getpeername()
message = recvall(sc, 16)
print 'The incoming sixteen-octet message says', repr(message)
sc.sendall('Farewell, client')
sc.close()
print 'Reply sent, socket closed'
net_py
socket.SO_REUSEADDR
NOTEs:
1: When a server passive socket is closed, TCP does not allow it to be
reused for several minutes to give all clients a chance to see that any future
listener is a new listener. If you want to rerun the program multiple times (as
in testing) then allow immediate reuse of the same passive socket.
2: If a popular server goes down you would want it to come back up immediately
and so for the same reason we set the SO_REUSEADDR socket option.
net_py
Example:
elif sys.argv[1:] == ['client']:
s.connect((HOST, PORT)) # can fail; unlike UDP
print 'Client has been assigned socket name', s.getsockname()
s.sendall('Hi there, server')
reply = recvall(s, 16)
print 'The server said', repr(reply)
s.close()
else:
print >>sys.stderr, 'usage: tcp_local.py server|client [host]'
NOTE: Calling send(), TCP might not send all bytes immediately and
returns the number actually sent;
calling sendall() asks that all data be sent asap and that happens before
the function call returns. Notice that program does not capture sendall()
return value.
NOTE: recv_all() loops until all expected data is received.
net_py
Tutorial
http://docs.python.org/2/howto/sockets.html#socket-howto
net_py
Exercises:

Create two sockets, one UPD and the other TCP and call
connect on both of them to a non-existent remote socket.
See what happens
[pletcha@archimedes 03]$ python
Python 2.7.3 (default, Jul 24 2012, 10:05:38)
>>> import socket
>>> udp_s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
>>> tcp_s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> udp_s.connect(('137.140.215.244',1060))
# [pletcha@archimedes 03]$ netstat -an | grep 215
# udp
0
0 192.168.1.124:42809 137.140.215.244:1060 ESTABLISHED
>>> tcp_s.connect(('192.169.1.124',1060))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 110] Connection timed out
>>>
net_py
TCP send()



The Stack has space so send() dumps all its data into a TCP
buffer and returns, even though nothing has been sent. From
now on, it is TCP's headache.
TCP buffer is full or Stack is busy so send() blocks
TCP buffer has some space but not enough for all send()
wants to transmit so send() moves as much data as it can
into the TCP buffer and returns that number. It is the
program's responsibility to recall send() with data starting at
the first byte not previously accepted by TCP.
net_py
TCP send() code:
bytes_sent = 0
while bytes_sent < len(message):
message_remaining = message[bytes_sent:]
bytes_sent += s.send(message_remaining)
# python has a sendall() function that does this for us.
net_py
TCP recv()

Works like send():

If no data then recv() blocks

if plenty available then gives back just what the call asks for

if some data available but not what you ask for you are gien
what is available and need to build up your own complete
message by repeatedly calling recv().
net_py
net_py
No TCP recvall()?





Because we hardly ever know in advance the precise size we
are expecting. For example, suppose we send out an HTTP
GET request to maps.google.com
The data that comes back consists of a header, a blank line
and some data.
The header may or may not contain a Content-Length field.
If it does we know exactly how many bytes to read so could
use a recvall() function. If not then we just need to read until
we feel we've come to the end of the data.
In Listing 1.5 this means until we come to the end of a
syntactically correct JSON data object, serialized.
net_py
HTTP/1.1 200 OK
Content-Type: text/javascript; charset=UTF-8
Vary: Accept-Language
Date: Wed, 21 Jul 2010 16:10:38 GMT
Server: mafe
Cache-Control: private, x-gzip-ok=""
X-XSS-Protection: 1; mode=block
Content-Length: 481
Connection: close
{
"name": "207 N. Defiance St, Archbold, OH",
"Status": {
"code": 200,
"request": "geocode"
},
"Placemark": [ {
...
"Point": {
"coordinates": [ -84.3063479, 41.5228242, 0 ]
}
}]
}
net_py
TCP State Diagram
net_py
TCP Segment
Options fields possible
net_py
TCP Header
net_py
TCP sliding window

Sliding-window protocol without selective or negative
acknowledgment.
data stream to be transmitted
sender
A
B
n1



C
n2
window direction
direction of data flow
window “belongs” to sender; each end of a connection has a
window
n1: byte (sequence) number of next byte to be transmitted for
the first time
n2: byte (sequence) number of next byte to be acknowledged
net_py

receiver
B: data already transmitted but not acknowledged
TCP Acknowledgment:



TCP does not “negative” acknowledge; ie, send a message
that something is missing
TCP does not “selectively” acknowledge; ie, send a message
that a specific byte range has been received
TCP acknowledgment number means TCP has received all
bytes up to but not including the ACK number.
net_py
TCP Flow Control


TCP sends a window size field in its header. This field is
used by the end that receives the TCP segment to control its
own sliding window size.
Typical window size is 4096. If the receiver end of a
connection sends a TCP header with a smaller number the
sender slows down transmission of new bytes until more
bytes are acknowledged by the other end (hence n1 – n2
shrinks)
net_py
TCP Options

MSS: Maximum Segment Size. Usually sent during 3-way
handshake so that both ends will know how big (or small)
future segments should be.
net_py
TCP Connect and Disconnect Timeline
net_py
TCP Timeout
Delay Sequence: 1, 2, 4 seconds
net_py
TCP Half-close
send() will fail;
recv() will be ok
net_py
TCP States
net_py
TCP MSL (Maximum Segment Lifetime)



MSL is the maximum time that a segment might expect to live
on the Internet while moving between the two hosts of a
connection.
When TCP performs an active close, and sends the final
ACK, that connection must stay in the TIME_WAIT state for
twice the MSL.
Prevents delayed segments from an earlier incarnation of the
same connection (srcIP,srcPort,destIP,destPort) from being
interpreted as part of the new connection
net_py
TCP FIN_WAIT_2

It is possible to stay in this state forever. Why?
net_py