以您熟悉的编程语言为例完成一个hello/hi的简单的网络聊天程序

在这片博文我们将使用python完成一个hello/hi的简单的网络聊天程序

 

先做一下准备工作

 

1.linux的socket基础api:

    使用socket()创建套接字

int socket(int af, int type, int protocol);

af为IP地址类型,AF_INE和AF_INET6分别对应ipv4和ipv6地址
type是数据传输方式,Sock_stream(面向连接套接字)和sock_dgram(无连接套接字)
protocol是传输协议,IPPROTO_TCP和IPPROTO_UDP

使用bind()将套接字与特定的ip地址和端口号绑定
int bind(int sock, struct sockaddr *addr, socklen_t addrlen); 
sock 为 socket 文件描述符,addr 为 sockaddr 结构体变量的指针,addrlen 为 addr 变量的大小

客户端使用connect()建立连接
int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);  


使用listen()函数让套接字进入被动监听状态
int listen(int sock, int backlog)
sock 为需要进入监听状态的套接字,backlog 为请求队列的最大长度。

使用 write() 可以向套接字中写入数据
ssize_t write(int fd, const void *buf, size_t nbytes)
fd 为要写入的文件的描述符,buf 为要写入的数据的缓冲区地址,nbytes 为要写入的数据的字节数

使用 read() 可以从套接字中读取数据
ssize_t read(int fd, void *buf, size_t nbytes);
fd 为要读取的文件的描述符,buf 为要接收数据的缓冲区地址,nbytes 为要读取的数据的字节数


2.python中相关的库

2.1socket库:这是python提供的基本的 低级别的网络服务,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法

  我们用 socket()函数来创建套接字,语法格式如下:

  socket.socket([family[, type[, proto]]])

  通过调用底层socket接口,提供有一下方法:

s.bind() 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。
s.listen() 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。
s.accept() 被动接受TCP客户端连接,(阻塞式)等待连接的到来
客户端套接字
s.connect() 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。
s.send() 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。

 

2.2 threading库:
  接受和发送消息的方法都是阻塞的,客户端和服务端之间要进行正常聊天,需要一个线程来接受对方的消息,另一个线程来发送消息,
  通过python的threading库来实现这个功能,示例如下:
  t=threading.Thread(target=tcp_recv, args=(s, addr))
  t.start()
 

3. 实现hello/hi的简单的网络聊天程序的python代码

 

客户端:

import socket
import threading
import time
from time import strftime, localtime

#定义套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接:
addr=('127.0.0.1', 9999)
s.connect(addr)

def tcp_recv(s,addr):
    while True:
        print(strftime("%Y-%m-%d %H:%M:%S", localtime()),s.recv(1024).decode('utf-8'))

t=threading.Thread(target=tcp_recv, args=(s, addr))
t.start()
while True:
    msg=input()
    # 发送数据:
    s.send((' From client : %s'% msg).encode('utf-8'))   
    if msg =='exit':
       break
s.send(b'exit')
s.close()

 

 

服务端:

import threading
import socket
from time import strftime, localtime

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 9999))
s.listen(5)
print('Waiting for connection...')

def tcp_recv(sock, addr):
    while True:
        data = sock.recv(1024)
        if not data or data.decode('utf-8') == 'exit':
            break
        
        print(strftime("%Y-%m-%d %H:%M:%S", localtime()),data.decode('utf-8'))
        #sock.send(('Server:%s'% input()).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)

def tcp_send(sock):
    while True:
       
        msg = input()
        if msg == 'exit':
            exit
        #print('Client:%s'%data.decode('utf-8'))
        sock.send((' From server : %s'% msg).encode('utf-8'))

    print('Connection from %s:%s closed.' % addr)

sock, addr = s.accept()
print('Accept new connection from %s:%s...' % addr)
sock.send(b' From server : Welcome!')

while True:
    # 接受一个新连接:
    # 创建新线程来处理TCP连接:
    t = threading.Thread(target=tcp_recv, args=(sock, addr))
    t.start()
    tcp_send(sock)
 
打开两个终端运行serve.py 和 client.py,运行结果应该是这样的:
服务端:
    

 

 

客户端:

 

 

 

posted @ 2019-12-11 17:55  zjce  阅读(311)  评论(0编辑  收藏  举报