socket

Socket

网络上两个程序通过socket接口进行通信,一个是服务器端,一个是客户端

socket则是对TCP/IP协议的封装和应用(程序员层面上)。
Socket本身并不是协议,而是一个调用接口(API)。
通过Socket,我们才能使用TCP/IP协议。
Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,
TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口

创建一个socket服务端:

客户端编程

  1. 创建 Socket
  2. 连接到远程服务器
  3. 发送数据
  4. 接收回应
创建socket
#Socket client example in python

import socket   #for sockets

#create an AF_INET, STREAM socket (TCP)
#返回 Socket 的描述符可用于其他 Socket 相关的函数
#地址簇 : AF_INET (IPv4)
#类型: SOCK_STREAM (使用 TCP 传输控制协议)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print 'Socket Created'
错误处理
#handling errors in python socket programs

import socket   #for sockets
import sys  #for exit

try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit();

print 'Socket Created'

注意

与 SOCK_STREAM 相对应的其他类型是 SOCK_DGRAM 用于 UDP 通讯协议,UDP 通讯是非连接 Socket,在这篇文章中我们只讨论 `SOCK_STREAM ,或者叫 TCP 。

2. 连接到服务器

连接到服务器需要服务器地址和端口号

首先获取远程主机的 IP 地址
import socket   #for sockets
import sys  #for exit
try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit();

print 'Socket Created'

host = 'www.baidu.com'
try:
    remote_ip = socket.gethostbyname( host )#获取远程主机的ip地址
except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()

print 'Ip address of ' + host + ' is ' + remote_ip

gethostbyname()–>用域名或主机名获取IP地址

已经有 IP 地址了,接下来需要 指定要连接的端口
创建了一个 Socket 并进行连接

import socket   #for sockets
import sys  #for exit

try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit();

print 'Socket Created'

host = 'www.baidu.com'
port = 80
try:
    remote_ip = socket.gethostbyname( host )
except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()
print 'Ip address of ' + host + ' is ' + remote_ip
#Connect to remote server
#连接远程服务器
s.connect((remote_ip , port))

print 'Socket Connected to ' + host + ' on ip ' + remote_ip

已经连接上了,接下来就是往服务器上 发送数据
使用 SOCK_STREAM/TCP 套接字才有“连接”的概念
UDP、ICMP 和 ARP 没有“连接”的概念

发送数据
import socket   #for sockets
import sys  #for exit

try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit();

print 'Socket Created'

host = 'www.oschina.net'
port = 80

try:
    remote_ip = socket.gethostbyname( host )

except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()

print 'Ip address of ' + host + ' is ' + remote_ip

#Connect to remote server
s.connect((remote_ip , port))

print 'Socket Connected to ' + host + ' on ip ' + remote_ipimport socket    #for sockets
import sys  #for exit

try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit();

print 'Socket Created'

host = 'www.oschina.net'
port = 80

try:
    remote_ip = socket.gethostbyname( host )

except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()

print 'Ip address of ' + host + ' is ' + remote_ip

#Connect to remote server
s.connect((remote_ip , port))

print 'Socket Connected to ' + host + ' on ip ' + remote_ip

#send sone data to remote server
message = "GET / HTTP/1.1\r\n\r\n"

try:
    #set the whole string
    #向远程服务器发送字符串数据 "GET / HTTP/1.1\r\n\r\n" ,这是一个 HTTP 协议的命令,用来获取网站首页的内容。
    s.sendall(message)
except socket.error:
    #send failed
    print 'send failed'
    sys.exit()
print 'Message send successfully'

接下来需要读取服务器返回的数据。

接收数据

recv 函数用于从 socket 接收数据

#Socket client example in python

import socket   #for sockets
import sys  #for exit

#create an INET, STREAMing socket
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
    print 'Failed to create socket'
    sys.exit()

print 'Socket Created'

host = 'oschina.net';
port = 80;

try:
    remote_ip = socket.gethostbyname( host )

except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()

#Connect to remote server
s.connect((remote_ip , port))

print 'Socket Connected to ' + host + ' on ip ' + remote_ip

#Send some data to remote server
message = "GET / HTTP/1.1\r\nHost: oschina.net\r\n\r\n"

try :
    #Set the whole string
    s.sendall(message)
except socket.error:
    #Send failed
    print 'Send failed'
    sys.exit()

print 'Message send successfully'

#now receive data
#从socket中接收服务器返回的数据
reply = s.recv(4096)
print reply

运行结果:

回应了我们所请求的 URL 的内容,很简单。数据接收完了,可以关闭 Socket 了

关闭 socket

s.close()

服务器端编程

  1. 打开 socket
  2. 绑定到一个地址和端口
  3. 侦听进来的连接
  4. 接受连接
  5. 读写数据
打开Socket
import socket
import sys
try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit();

print 'Socket Created'
绑定socket

bind()将 Socket 绑定到一个特定的地址和端口(自己写的服务器)
需要一个类似 connect 函数所需的 sockaddr_in 结构体。

import socket
import sys

HOST = ''   # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'

try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

print 'Socket bind complete'

绑定完成后,就需要让 Socket 开始侦听连接。
很显然,你不能将两个不同的 Socket 绑定到同一个端口之上。

连接侦听

需要将 Socket 变成侦听模式
socket 的 listen 函数用于实现侦听模式:
参数:backlog,用来控制程序忙时可保持等待状态的连接数

s.listen(10)
print 'Socket now listening'
接受连接

s.accept()–>
接受TCP连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。
s.accept()–>接收客户端的请求

import socket
import sys

HOST = ''   # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'

try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

print 'Socket bind complete'

s.listen(10)
print 'Socket now listening'

#wait to accept a connectiong - blocking call
#等待接收连接
#conn是新的套接字对象,可以用来接收和发送数据。
#address是连接客户端的地址。
conn,addr = s.accept()

#display client information
#展示客户端信息
print 'connected with' + addr[0] + ':' + str(addr[1])

让我们来给客户端做出点回应
sendall 函数可通过 Socket 给客户端发送数据

一直在运行的服务器
import socket
import sys
#自己给定的主机和端口
HOST = ''   # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'

try:
    #接收的是一个元组
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

print 'Socket bind complete'
#监听从客户端来的请求
s.listen(10)
print 'Socket now listening'

while 1#wait to accept a connection - blocking call
    conn, addr = s.accept()#建立连接,并返回1 新的套接字2.客户端地址

    print 'Connected with ' + addr[0] + ':' + str(addr[1])

    #对请求进行处理
    # now keep talking with the client
    #把接收的数据实例化
    data = conn.recv(1024)#用新的套接字接收数据,并实例化
    #结果发给对端(即客户端)
    conn.sendall(data)#sendall 函数可通过 Socket 给客户端发送数据

conn.close()
s.close()

运行结果:


可看到客户端已经成功连接到服务器

处理多个连接请求
import socket
import sys
from thread import *

HOST = ''   # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'

#Bind socket to local host and port
try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

print 'Socket bind complete'

#Start listening on socket
s.listen(10)
print 'Socket now listening'

#function for handling connections,this will be used to create threads
def clientthread(conn):
    #send message to connected client
    ##send only takes string
    #发送到客户端
    conn.send("welcome to the server.type something and hit enter\n")
    #infinite loop so that function do not terminate and thread do not end

    while True:
        #receiving from client
        #循环从客户端接收数据
        data = conn.recv(1024)
        reply = 'OK...' +data
        if not data:
            break
        #向客户端发送“OK...”,客户端中显示OK表明发送成功
        conn.sendall(reply)
    #came out of loop
    conn.close()
while 1:
    #wait to accept a connection - blocking call
    conn,addr = s.accept()
    print 'Connected with' + addr[0] + ':' + str(addr[1])

    #start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
    start_new_thread(clientthread ,(conn,))#进入clientthread执行

s.close()

start_new_thread ( function , args [ , kwargs ] )
创建一个新的线程,返回一个线程标识符。
function是线程函数,
args是线程函数的参数,是一个list。
kwargs可选参数,可不填。

线程接管了连接并返回相应数据给客户端。

这便是我们所要介绍的服务器端编程。

================================================================================

socket编程思路

TCP服务端:
1. 创建套接字,绑定套接字到本地IP与端口
# socket.socket(socket.AF_INET,socket.SOCK_STREAM) , s.bind()
2. 开始监听连接 #s.listen()
3. 进入循环,不断接受客户端的连接请求 #s.accept()
4. 然后接收传来的数据,并发送给对方数据 #s.recv() , s.sendall()
5. 传输完毕后,关闭套接字 #s.close()

Socket编程之服务端代码:

    import socket   #socket模块
import commands   #执行系统命令模块
HOST='10.0.0.245'
PORT=50007
s= socket.socket(socket.AF_INET,socket.SOCK_STREAM)   #定义socket类型,网络通信,TCP
s.bind((HOST,PORT))   #套接字绑定的IP与端口
s.listen(1)         #开始TCP监听
while 1:
       conn,addr=s.accept()   #接受TCP连接,并返回新的套接字与IP地址
       print'Connected by',addr    #输出客户端的IP地址
       while 1:
                data=conn.recv(1024)    #把接收的数据实例化
               cmd_status,cmd_result=commands.getstatusoutput(data)   #commands.getstatusoutput执行系统命令(即shell命令),返回两个结果,第一个是状态,成功则为0,第二个是执行成功或失败的输出信息
                if len(cmd_result.strip()) ==0:   #如果输出结果长度为0,则告诉客户端完成。此用法针对于创建文件或目录,创建成功不会有输出信息
                        conn.sendall('Done.')
                else:
                       conn.sendall(cmd_result)   #否则就把结果发给对端(即客户端)
conn.close()     #关闭连接

Socket编程之客户端代码:

    import socket
HOST='10.0.0.245'
PORT=50007
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)      #定义socket类型,网络通信,TCP
s.connect((HOST,PORT))       #要连接的IP与端口
while 1:
       cmd=raw_input("Please input cmd:")       #与人交互,输入命令
       s.sendall(cmd)      #把命令发送给对端
       data=s.recv(1024)     #把接收的数据定义为变量
        print data         #输出变量
s.close()   #关闭连接

参考:
https://www.oschina.net/question/12_76126
http://yangrong.blog.51cto.com/6945369/1339593

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值