Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2568322
  • 博文数量: 315
  • 博客积分: 3901
  • 博客等级: 少校
  • 技术积分: 3640
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-08 15:32
个人简介

知乎:https://www.zhihu.com/people/monkey.d.luffy Android高级开发交流群2: 752871516

文章分类

全部博文(315)

文章存档

2019年(2)

2018年(1)

2016年(7)

2015年(32)

2014年(39)

2013年(109)

2012年(81)

2011年(44)

分类: Python/Ruby

2012-02-22 21:42:43

                                                               网络

          关于核心编程的第二部分的网络相关的东西,还是蛮有用的,和以前学习c的时候差不多,很多函数都类似甚至相同,虽然文章将的不细,但对于网络的学习还是有帮助的。多了解点是点,多学点是点

          一》下面就是文章的例子:(至于关于tcp, udp,套接字等概念,越清晰越好)

          TCP服务器端:tsTserv.py

#!/usr/bin/env python

# -*- coding: UTF-8 -*-

 

from socket import *

from time   import ctime

 

if __name__ == "__main__":

    HOST = '' #表示可以接受所有有效地址

    PORT = 21567

    BUFSIZE = 1024 #数据缓冲区

    ADDR = (HOST, PORT)

    tcpSerSock = socket(AF_INET, SOCK_STREAM) #1>创建一个网络流套接字

    tcpSerSock.bind(ADDR) #2>绑定

    tcpSerSock.listen(10) #3>可以监听10

 

    while True: #利用进程来做是最好的!

        print 'Waitting for connection...'

        tcpCliSock, addr = tcpSerSock.accept() #4>阻塞等待接受,返回对方地址和一个新的套接字对象,就是以元组的方式存储起来,这里我们分别赋值给tcpCliSock, addr, udp中我们就用一个元组对象来存储,然后同过下标值访问即可

        print '...connected from:', addr

        while True:

            data = tcpCliSock.recv(BUFSIZE) #5>获取对方发送的数据,一般为请求的服务,并存储在缓冲区中

            if not data: #没有数据就等待下次连接

                break

            tcpCliSock.send('[%s] %s' % (ctime(), data)) #6>将接受的数据加上时间应答给客户,收发都可以自己定

           

            tcpCliSock.close() #7>注意完成客户/服务器操作要关闭,否则会占有大量的网络资源;但是如果用户还没关闭,就不能关闭,但是对于一般用户请求基本就进行一次交互就关闭,避免占有资源!

            break #为了完成一次交互,我停止循环,不如服务器无法接受更多请求,和上句一起放在内层while之外就可以无限交互

 

    tcpSerSock.close() #最后关闭监听的服务器

 

          TCP客户端:  tsTlnt.py

#!/usr/bin/env python

# -*- coding: UTF-8 -*-

 

from socket import *

 

if __name__ == "__main__":

    HOST = 'localhost' #本地主机名

    PORT = 21567 #服务器端口

    BUFSIZE = 1024 #缓冲区一般是4的整数倍

    ADDR = (HOST, PORT)

 

    tcpCliSock = socket(AF_INET, SOCK_STREAM) #1>套接字创建, 类型和服务器一样

    tcpCliSock.connect(ADDR) #2>建立连接

   

    while True:

        data = raw_input('>')

        if not data:

            break

        tcpCliSock.send(data) #3>发送数据,一般应用中发送请求,服务器再去应答你的服务

        data = tcpCliSock.recv(BUFSIZE) #4>接受服务器返回的数据,在实际应用中,收发数据的数据说不准了,而且可能会有很多层嵌套,尤其在做文件服务器的时候,为了区分不同的命令,你需要多次进行客户/服务器的应答交互

        #print '---data--', data #到这里出错了,没数据,发现是我的服务器每次接受完一个连接,收发完一次数据后,又等待连接出错的,一旦连接上这一次就不该断开

        if not data:

            break

        print data

 

        tcpCliSock.close() #5>同样记住,完成交互后记得关闭

        break #就一次交互,当然将上句和这句提到while之外就可以无限交互了,这样太死了;看了得用进程来做了

 

          UDP服务器端:tsUserv.py

#!/usr/bin/env python

# -*- coding: UTF-8 -*-

 

from socket import *

from time   import ctime

 

if __name__ == "__main__":

    HOST = ''

    PORT = 21567

    BUFSIZE = 1024

    ADDR = (HOST, PORT)

 

    udpSerSock = socket(AF_INET, SOCK_DGRAM)

    udpSerSock.bind(ADDR) #完了后,没有设置像tcp的最大连接数

 

try:

    while True: #udp中不需要像tcpaccept()这样的操作,因为我们一种类似广播这样的通信机制,是无连接的,不需要很高的可靠性;同时为了减少三次握手的时间消耗

        print 'Waitting for message...'

        

        #data, addr = udpSerSock.recvfrom(BUFSIZE) #可以被元组替代,不过还是这种写法清晰,推荐这种

        #udpSerSock.sendto('[%s] %s' % (ctime(), data), addr) #拼接了时间和数据,并且发送

       

        data_addr = udpSerSock.recvfrom(BUFSIZE)

        udpSerSock.sendto('[%s] %s' % (ctime(), data_addr[0]), data_addr[1]) #拼接了时间和数据,并且发送

        print '...received from and returned to: ', data_addr[1]

except KeyboardInterrupt:

    print 'bye.....'

    udpSerSock.close() #服务器还是让它一直运行,这个关闭应该放在异常捕捉里面(比如键盘中断KeyboardInterrrupt)

 

          UDP客户端:  tsUclnt.py

#!/usr/bin/env python

# -*- coding: UTF-8 -*-

 

from socket import *

 

if __name__ == "__main__":

    HOST = 'localhost' #本机地址

    PORT = 21567

    BUFSIZE = 1024

    ADDR = (HOST, PORT)

 

    udpCliSock = socket(AF_INET, SOCK_DGRAM)

 

    while True:

        data = raw_input('>')

        if not data:

            break

        udpCliSock.sendto(data, ADDR) #客户端就发送数据,然后接收返回数据

        data, ADDR = udpCliSock.recvfrom(BUFSIZE)

        if not data:

            break

        print data

udpCliSock.close()

 

后面还有利用python封装好的服务器类来做自己的服务器,主要就是自己实现handler接口,然后传入类中即可,可以大大减少代码量的编写,不过另一方面也让人变懒了..呵呵

最后有个关于Twisted框架,就是一个事件驱动的网络框架,我的理解就是一个代码框架,我们导入它,去重新它的方法,来达到我们的要求,而这个框架就是一个模块似的。

# file: twisted.py

#!/usr/bin/env python

 

from twisted.internet import protocol, reactor

from time import ctime

 

PORT = 21567

 

class TSServProtocol(protocol.Protocol):

    def connectionMade(self):

        clnt = self.clnt = self.transport.getPeer().host #通过类对象来得到本地主机名

        print '...connected from:', clnt

        def dataReceived(self, data): #重写数据接收函数

            self.transport.write('[%s] %s' % (ctime(), data))

           

factory = protocol.Factory() #工厂:每连接一个就会创建一个这样的实例

factory.protocol = TSServProtocol #利用twisted框架做的自己的服务器

print 'waiting for connection...'

reactor.listenTCP(PORT, factory)

reactor.run()

 

我们有必要去看下以前练习的Ctcp的编程,以此来比较下有何不同;(其实大同小异了python似乎基本上是c实现的,还有类的话,编译器估计还有些其他lg,有必要了解下,光顾着学它去了)

//file: main.c    //这是c的主函数,其他函数都在相应文件,这是服务器端的主要流程,一样的,不过c需要处理网络字节流的问题;其实python也有相关的处理函数,看了下,和c的差不多

#include

#include

#include

#include

#include

#include

#include

#include          

#include

#include

#include

#include

 

#include "service.h"

#include "common.h"

 

int general_flag; //just for return value test

int general_n;    //just for return bytes test

 

//--------------------------------------------------------------------

// Function prototype

//------------------------------------------------------------------

void sigchild_handler(int sig);

 

int main(int argc, const char *argv[])

{

    unsigned short port;

    int backlog;

    port = (unsigned short )strtol("5000", NULL, 10);

    backlog = (unsigned short )strtol("10", NULL, 10);

 

    //define buffer

    char buffer[BUFFER_SIZE];

    memset(buffer, 0, sizeof(buffer)); //*******remember this

 

    //-----------------------------------------------------------------------

    //create socket

    //-----------------------------------------------------------------------

    //1 step: create socket

    //int socket(int domain, int type, int protocol);

    int listening_socket;

    if((listening_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)

    {

        fprintf(stdout, "socket failed %s\n", strerror(errno));

        exit(1);

    }

 

    fprintf(stdout, "Create socket success, listning = %d \n", listening_socket);

 

    int optval;

    optval = 1;

 

    //-----------------------------------------------------------------------

    //setsockopt

    //-----------------------------------------------------------------------

    //int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);

    if(setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)

    {

        fprintf(stderr, "Set SO_REUSEADDR on liste    ning_socket failed: %s\n", strerror(errno));

    }

 

    fprintf(stderr, "Set SO_REUSEADDR on listeni    ng_socket successfully.\n");

 

#ifdef SO_REUSEPORT

    optval = 1;

 

    if(setsockopt(listening_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) < 0)

    {

        fprintf(stderr, "Set SO_REUSEPORT on liste    ning_socket failed: %s\n", strerror(errno));

    }

 

    fprintf(stderr, "Set SO_REUSEPORT on listeni    ng_socket successfully.\n");

#endif

    //-----------------------------------------------------------------------

    //bind

    //-----------------------------------------------------------------------

    //2 step: bind

    //int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

    struct sockaddr_in servaddr;

 

    memset(&servaddr, 0, sizeof(servaddr));

    servaddr.sin_family = AF_INET;

    servaddr.sin_port = htons(port);

 

    //int inet_pton(int af, const char *src, void *dst);

    general_flag = inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

    if(general_flag < 0)

    {

        fprintf(stdout, "analysis failed %s\n", strerror(errno));

        //FIXME again!

    }

 

    if(bind(listening_socket, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)

    {

        fprintf(stdout, "bind to %s failed, port = %d  %s\n", argv[1], port, strerror(errno));

        exit(1);

    }

    fprintf(stdout, "Bind to %s success, port = %d\n", argv[1], port);

 

    //-----------------------------------------------------------------------

    //listenning

    //-----------------------------------------------------------------------

    //3 step: listenning

    //int listen(int sockfd, int backlog);

    if((general_flag = listen(listening_socket, backlog)) < 0)

    {

        fprintf(stdout, "listenning failed %s\n", strerror(errno));

        exit(1);

    }

 

    fprintf(stdout, "listenning success\n");

 

    //------------------------------------------------------------------

    // Set signal handler

    //------------------------------------------------------------------

    //typedef void (*sighandler_t) (int);

    //sighandler_t signal(int signum, sighandler_t handler);

    signal(SIGCHLD, sigchild_handler);

 

    //-----------------------------------------------------------------------

    //accept, create new socket

    //-----------------------------------------------------------------------

    //4 step: accept, create new socket

    //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    //int socket(int domain, int type, int protocol);

    struct sockaddr_in clientaddr;

    socklen_t clientaddr_len;

 

    printf("Acceting connections ...\n");

    while(1)

    {

        clientaddr_len = sizeof(clientaddr);

 

        int fd = accept(listening_socket, (struct sockaddr*)&clientaddr, &clientaddr_len); //这个地方在接收的时候返回的是一个类似文件描述符的整型数据,而python中对于---tcp来说则是套接字对象和地址信息的元组,对于—udp来说则是数据和地址的元组.

        if(fd < 0)

        {

            fprintf(stdout, "accept client ip = %s, port = %s Failed :%s\n", argv[1], argv[2], strerror(errno));

            //FIXME how to do?

            break;

        }

        else

        {

            // TODO: Add black list or white list to filter incoming connections

            pid_t pid;

            pid = fork();

            if(pid < 0)

            {

                perror("failed to create process\n");

                exit(1);

            }

            else if(0 == pid)

            {

                // child process

                //--------------------------------------------------------------------------

                //Close parent's listening_socket

                //--------------------------------------------------------------------------

                close(listening_socket);

 

                //--------------------------------------------------------------------------

                // r/w

                //--------------------------------------------------------------------------

 

                //5 step: read the client sended information

                //ssize_t read(int fd, void *buf, size_t count);

 

                general_n = read(fd, buffer, BUFFER_SIZE);

                if(general_n < 0)

                {

                    fprintf(stdout, "read from client failed %s\n", strerror(errno));

                    //FIXME how to do?

                    break;

                }

               

                //TODO read the request, then need to return request?

                //to handler request

                fprintf(stdout, "-------receive data is %s\n", buffer);

                strtok_command(fd, buffer);

 

                //--------------------------------------------------------------------------

                //close new_connected_socket

                //--------------------------------------------------------------------------

                close(fd);

 

                //------------------------------------------------------------------------

                //Terminate

                //--------------------------------------------------------------------------

                exit(0);

            }

            else

            {

                close(fd);

            }

        }

    }

 

    close(listening_socket);

 

    return 0;

}

 

void sigchild_handler(int sig) //信号处理,就简单打印了点信息

{

    fprintf(stdout, "[%d] Caught signal %d.\n", getpid(), sig);

}

 

      二》因特网协议(ftp—文件传输协议(基于tcp)NNTP—网络新闻传输协议,POP3协议邮件接收协议,SMTP—邮件发送协议,还有很多了,不列举了…)

      这是利用SMTPPOP3协议编写的收发邮件的例子(myMail.py)(电脑不能上网,不能测试了)

#!/usr/bin/env python

# -*- coding: UTF-8 -*-

 

#---这些因特网协议都是基于低级别的协议TCP/IP来创建新的,更具体的,符合我们需要的服务;至于更加深入的内容,需要花力气了

 

from smtplib import SMTP

from poplib  import POP3

from time    import sleep

 

if __name__ == "__main__":

    SMTPSVR = 'smtp.python.is.cool' #SMTP用于发送服务器,修改为自己的邮箱服务器;比如smtp.163.com

    POP3SVR = 'pop.python.is.cool' #POP3用于接收邮件的服务器

   

    #以下是构建消息头,消息体和消息内容,组合成一个完整的消息

    #依据Sendmail(from, to, msg[,mopts, ropts])函数原型来构造

    origHdrs = ['From:wesley@python.is.cool', \

               'To:wesley@python.is.cool', \

               'Subject: test msg']

    origBody = ['xxx', 'yyy', 'zzz']

    #按要求需要在消息前加入两个回车和换行;在头和体时加入一个回车和换行,这是RFC文档要求

    origMsg  = '\r\n\r\n'.join(['\r\n'.join(origHdrs), \

                '\r\n'.join(origBody)])

    try: #后面很多地方都需要出错处理的...

        sendSvr = SMTP(SMTPSVR)

    except (socket.error, socket.gaierror), e:

        print 'ERROR: cannot reach "%s" \n "%s"' % (SMTPSVR, e)

        return

    print '***Connected  to host "%s"' % SMTPSVR

   

    errs = sendSvr.sendmail('wesley@python.is.cool', \

            ('wesley@python.is.cool',), origMsg)

    sendSvr.quit()

    assert len(errs) == 0, errs #断言是否有错误,有的话,那么值就不是0,出错,并打印错误信息;否则跳过

    sleep(10) #延迟等待发送

 

    #POP3接受消息比SMTP简单多了;可以利用内建函数来设置用户和密码

    recvSvr = POP3(POP3SVR)

    recvSvr.user('wesley')

    recvSvr.pass_('yourNeverGuess')

    rsp, msg, size = recvSvr.retr(recvSvr.stat()[0]) #返回一个三元组,返回信息,消息,和字节数;stat用于获取有效的消息列表,然后选取第一条消息

    sep = msg.index('') #我们空行来分割头和消息,去掉头部分

    recvBody = msg[sep+1:] #不是很明白,模糊?

    assert origBody == recvBody #断言是否相等,不等则显示断言失败错误

阅读(2548) | 评论(0) | 转发(0) |
0

上一篇:python代码执行

下一篇:python 网络(web)

给主人留下些什么吧!~~