何为 socket ?
- 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
流程
- 1、服务器绑定 ip 地址和端口号
- 2、服务器监听端口号请求,随时接受客户端发来的请求链接 (这个时候还没办法链接)
- 3、客户端创建 socket
- 4、客户端打开 socket 根据 ip 和端口号 尝试链接服务器的 socket
- 5、服务器 socket 接受客户端 socket 请求,接受客户端的请求,等客户端返回链接信息,然后进入阻塞状态(即 acept 方法 等客户端返回链接信息 才返回,开始接收下一个客户端请求)
- 6、客户端 socket 链接成功,向服务器 socket 发送状态信息
- 7、服务器返回信息,链接成功
- 8、客户端 向 服务器 写入信息
- 9、服务器接收信息 再像客户端发送信息(客户端读取信息)
- 10、 客户端 和 服务端关闭
我这边用的 Python 3.x 的版本 来写的服务器 socekt ,里面方法如图
服务端一次接收和发送 代码如下
import socket # 导入socket模块
sk = socket.socket() # 创建socket对象
sk.bind(("127.0.0.1", 6768)) # 绑定端口,“127.0.0.1”代表本机地址,8888为设置链接的端口地址
sk.listen(5) # 设置监听,最多可有5个客户端进行排队
conn, addr = sk.accept() # 阻塞状态,被动等待客户端的连接
print(conn) # conn可以理解客户端的socket对象
#
print(addr) # addr为客户端的端口地址
# ('127.0.0.1', 40966)
accept_data = conn.recv(1024) # conn.recv()接收客户端的内容,接收到的是bytes类型数据,
accept_data2 = str(accept_data, encoding="utf8") # str(data,encoding="utf8")用“utf8”进行解码
print("".join(("接收内容:", accept_data2, " 客户端口:", str(addr[1]))))
send_data = input("输入发送内容:")
conn.sendall(bytes(send_data, encoding="utf8")) # 发送内容必须为bytes类型数据,bytes(data, encoding="utf8")用“utf8”格式进行编码
conn.close()
简单的并发 服务端
import socketserver # 导入socketserver模块
class MyServer(socketserver.BaseRequestHandler): # 创建一个类,继承自socketserver模块下的BaseRequestHandler类
def handle(self): # 要想实现并发效果必须重写父类中的handler方法,在此方法中实现服务端的逻辑代码(不用再写连接准备,包括bind()、listen()、accept()方法)
while 1:
conn = self.request
addr = self.client_address
# 上面两行代码,等于 conn,addr = socket.accept(),只不过在socketserver模块中已经替我们包装好了,还替我们包装了包括bind()、listen()、accept()方法
while 1:
accept_data = str(conn.recv(1024), encoding="utf8")
print(accept_data)
if accept_data == "byebye":
break
send_data = bytes(input(">>>>>"), encoding="utf8")
conn.sendall(send_data)
conn.close()
if __name__ == '__main__':
sever = socketserver.ThreadingTCPServer(("127.0.0.1", 6768),
MyServer) # 传入 端口地址 和 我们新建的继承自socketserver模块下的BaseRequestHandler类 实例化对象
sever.serve_forever() # 通过调用对象的serve_forever()方法来激活服务端
想在 Python 建立客户端 代码如下
import socket
sk = socket.socket()
sk.connect(("127.0.0.1", 6768)) # 主动初始化与服务器端的连接
while True:
send_data = input("输入发送内容:")
sk.sendall(bytes(send_data, encoding="utf8"))
if send_data == "byebye":
break
accept_data = str(sk.recv(1024), encoding="utf8")
print("".join(("接收内容:", accept_data)))
sk.close()
iOS 端主要代码
@property (nonatomic, strong) NSInputStream *inputStream;//对应输入流
@property (nonatomic, strong) NSOutputStream *outputStream;//对应输出流
// 建立连接
NSString *host = @"127.0.0.1";
int port = 6768;
// 定义C语言输入输出流
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
// 把C语言的输入输出流转化成OC对象
_inputStream = (__bridge NSInputStream *)(readStream);
_outputStream = (__bridge NSOutputStream *)(writeStream);
// 设置代理
_inputStream.delegate = self;
_outputStream.delegate = self;
#warning 缺少该步骤,代理有可能不工作
// 把输入输入流添加到主运行循环
[_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
// 打开输入输出流
[_inputStream open];
[_outputStream open];
#pragma mark - NSStreamDelegate
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
NSLog(@"%@",[NSThread currentThread]);
// NSStreamEventOpenCompleted = 1UL << 0,//输入输出流打开完成
// NSStreamEventHasBytesAvailable = 1UL << 1,//有字节可读
// NSStreamEventHasSpaceAvailable = 1UL << 2,//可以发放字节
// NSStreamEventErrorOccurred = 1UL << 3,// 连接出现错误
// NSStreamEventEndEncountered = 1UL << 4// 连接结束
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(@"输入输出流打开完成");
break;
case NSStreamEventHasBytesAvailable:
NSLog(@"有字节可读");
[self readData];
break;
case NSStreamEventHasSpaceAvailable:
NSLog(@"可以发送字节");
break;
case NSStreamEventErrorOccurred:
NSLog(@" 连接出现错误");
break;
case NSStreamEventEndEncountered:
NSLog(@"连接结束");
// 关闭输入输出流
[_inputStream close];
[_outputStream close];
// 从主运行循环移除
[_inputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
break;
default:
break;
}
}
//建立一个缓冲区 可以放1024个字节
uint8_t buf[1024];
// 返回实际装的字节数
NSInteger len = [_inputStream read:buf maxLength:sizeof(buf)];
// 把字节数组转化成字符串
NSData *data = [NSData dataWithBytes:buf length:len];
// 从服务器接收到的数据
NSString *recStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//把Str转成NSData
NSData *data = [model.text dataUsingEncoding:NSUTF8StringEncoding];
// 发送数据
[weakSelf.outputStream write:data.bytes maxLength:data.length];
最后就变成这样了,界面是随意写的 有点丑 别介意!
写文章不易,给个喜欢可否?