网络编程里,socket编程是最基础的,其他网络编程都是在它的基础上封装得来的
socket对象,AF_INET 代表ipv4,AF_INET6 代表ipv6,AF_UNIX,unix才有
SOCKET_STREAM 代表有tcp。SOCK_DGRAM 代表udp
**client没什么功能。server的功能比较多
TCP有client有server
**
socket有IP,协议,端口,端口监听之前需要先绑定bind一下,监听listen端口
然后accept,接收客户端链接,等待链接,接收链接后,accept会返回新的socket和远端的地址和端口,通过它accept返回的新的socket跟客户端之间建立链接,这两个socket建立通道交换数据
socket是占用文件描述符的,用完需要归还
client通过指定远程的ip端口,尝试和socket进行链接,accept看到有人来链接,会把这个client链接跟一个新的socket建立链接,
client就和new socket 建立链接了
accept和recv会阻塞住,一个主线程阻塞住,就不能变成群聊了,可以使用多线程,accept就扔到一个线程理
tcp server里面开多个线程,把accept放到单独线程里,这样主线程可以进行管理的工作,网络也属于IO,IO密集型就是多线程
也就是现在的版本,有个ChatServer类,创建socket,初始化IP,端口,listen之后要accept,但是accept会阻塞,就需要开一个线程,每accept一次就创建一个新的线程,
与客户端连接就创建一个新的线程,把socket传递进去,new socket就管理和客户端的通信问题,如果阻塞,最好的办法就是以后开多线程放进去
做资源释放
群聊,就需要记住客户端,就要有个容器存放socket,但是有个删除的过程,就是一个字典
元组能不呢个做字典的key就需要看里面的元素是不是可hash
看到的消息群发给客户端
运行一下,accept启动
1对1没有问题
另外的也可以收到消息,这就是群聊
while TRUE 可以用event代替
创建多线程的event
所有的while true替换一下
客户端应该有个断开机制,进行收尾的工作,比如客户端发送quit,告诉服务器不想跟你玩了
也就是recv拿到消息,要判断这个消息
可以使用strip,判断后面quit字符串如果加了空格算不算退出,可以把两头的空白字符去掉
退出,首先需要把它从字段剔除掉,使用pop(),每个线程启动传入的都是不同的sock和raddr,只要这个线程不退出,sock和raddr都存在
break 以后,,socket关掉,线程就执行完了
pop是有返回值的,可以这么写,但是看起来不舒服,暂时不这么写
客户端发送quit,主动退出,就会在列表里把你直接清除掉。然后socket.close,这里是内建数据结构,GIL这把锁,所以多线程可以这么写,但是JAVA就不可以这么写了(因为有可能其他线程正在读,不能pop,有的线程在读,有的线程在写,不加锁是不行的)
发消息两个都收到了,断其中的一个
另外一个发送消息,但是收是收到了,有一个小问题
问题出在这里
添加一些表明的代码,再次重复刚才的两个链接发消息,然后断开一个
现在这里收到一个空的东西,也就是断开的时候,主动发送一个空串、这里报的windows的错误,底层操作系统对socket的实现还是有些不一样的,windows开发的软件
现在发送一个消息,两个客户端都可以收到
点这个断开会发送一个空串
用自己些的quit
现在就剩一个链接了
现在CS之间进行了一种约定,何时才断开
点软件的断开,就会出现错误
收到一个空串
对38行代码进行修改
再次点链接断开,只要我们断开,其实就给我们发送一个空串
所以可以这么写,空串或者quit的时候也会断开
现在就断开了,不报错
一种是自己写的quit机制,另一个是直接断开链接,服务器端会看到空串,这样直接判断空串也是可以的,断开的时候要做资源的清理,从列表摘除
客户端断开,服务器不知道,但是这里会发送空串,就可以用这个来判断断开
format第一个就是fmt
logging,info如果没有handler还是要强制创建handler,创建之后才调用inforoot必须有handler