socket

来源:互联网 发布:开关电源仿真软件psim 编辑:程序博客网 时间:2024/06/03 22:47

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 pythonimport 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 programsimport socket   #for socketsimport sys  #for exittry:    #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 socketsimport sys  #for exittry:    #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 socketsimport sys  #for exittry:    #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 = 80try:    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 socketsimport sys  #for exittry:    #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 = 80try:    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 servers.connect((remote_ip , port))print 'Socket Connected to ' + host + ' on ip ' + remote_ipimport socket    #for socketsimport sys  #for exittry:    #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 = 80try:    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 servers.connect((remote_ip , port))print 'Socket Connected to ' + host + ' on ip ' + remote_ip#send sone data to remote servermessage = "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 pythonimport socket   #for socketsimport sys  #for exit#create an INET, STREAMing sockettry:    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 servers.connect((remote_ip , port))print 'Socket Connected to ' + host + ' on ip ' + remote_ip#Send some data to remote servermessage = "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 socketimport systry:    #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 socketimport sysHOST = ''   # Symbolic name meaning all available interfacesPORT = 8888 # Arbitrary non-privileged ports = 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 socketimport sysHOST = ''   # Symbolic name meaning all available interfacesPORT = 8888 # Arbitrary non-privileged ports = 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 socketimport sys#自己给定的主机和端口HOST = ''   # Symbolic name meaning all available interfacesPORT = 8888 # Arbitrary non-privileged ports = 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 socketimport sysfrom thread import *HOST = ''   # Symbolic name meaning all available interfacesPORT = 8888 # Arbitrary non-privileged ports = socket.socket(socket.AF_INET, socket.SOCK_STREAM)print 'Socket created'#Bind socket to local host and porttry:    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 sockets.listen(10)print 'Socket now listening'#function for handling connections,this will be used to create threadsdef 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=50007s= socket.socket(socket.AF_INET,socket.SOCK_STREAM)   #定义socket类型,网络通信,TCPs.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 socketHOST='10.0.0.245'PORT=50007s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)      #定义socket类型,网络通信,TCPs.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

原创粉丝点击