iOS原生Socket编程
一、Socket连接原理
- 1、原理流程图
二、客户端编程代码
- 1、初始化准备数据
//引入头文件
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
//htons将一个无符号整型数据转为网络字节顺序,不同cpu是不同的顺序
#define SOCKET_PORT htons(8040)
//ip地址:以本地为例子
#define IP_ADRR "127.0.0.1"
- 2、创建soket
//创建socket
/// int socket(int family, int type, int protocol);
///参数一:family:协议簇或者协议域(AF_INET:IPv4协议;AF_INET6:IPv6协议;AF_LOCAL:Unix域协议;AF_ROUTE:路由套接字;AF_KEY:密钥套接字)
///参数二:type:套接字类型(SOCK_STREAM:字节流套接字;SOCK_DGRAM:数据包套接字;SOCK_EQPACKET:有序分组套接字;SOCK_RAW:原始套接字)
///参数三:protocol协议类型(IPPROTO_TCP:TCP传输协议;IPPROTO_UDP:UDP传输协议;IPPROTO_SCTP:SCTP传输协议;0:选择所给定family和type组合的系统默认值)
int socketId = socket(AF_INET, SOCK_STREAM, 0);
self.clientId = socketId;
if (socketId == -1) {
NSLog(@"create socket fail");
return;
}
- 3、socket连接
//连接socket
struct sockaddr_in socketAdrr;
socketAdrr.sin_family = AF_INET;
socketAdrr.sin_port = SOCKET_PORT;
struct in_addr socketIn_adrr;
socketIn_adrr.s_addr = inet_addr(IP_ADRR);
socketAdrr.sin_addr = socketIn_adrr;
///int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen)
///参数一:sockfd(socket描述符)
///参数二:servaddr(socket地址结构体指针)
///参数三:addrlen(socket地址结构体大小)
int result = connect(socketId, (const struct sockaddr *)&socketAdrr, sizeof(socketAdrr));
if(result != 0){
NSLog(@"客户端:连接失败");
return;
}
- 4、接受信息
///异步接受信息,防止阻塞主线程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self recvMsg];
});
- (void)recvMsg{
while (1) {
uint8_t buffers[1024];
///ssize_t recv(int, void *, size_t, int)
///参数一:socket标志符
///参数二:缓冲区
///参数三:缓冲区大小
///参数四:指定调用方式,一般设置为0
ssize_t sizeLen = recv(self.clientId, buffers, sizeof(buffers), 0);
NSLog(@"客户端:接收到%zd个字节",sizeLen);
if(sizeLen == 0){
continue;
}
NSData *data = [NSData dataWithBytes:buffers length:sizeLen];
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"客户端:%@ 接收到消息:%@",[NSThread currentThread],msg);
}
}
- 5、发送消息
- (void)sendMsg:(NSString *)msg{
if(msg.length <= 0) return;
const void *buff = msg.UTF8String;
///ssize_t write(int __fd, const void * __buf, size_t __nbyte)
///参数一:socket标志符
///参数二:缓冲区
///参数三:缓冲区大小
ssize_t sizeLen = write(self.clientId, buff, strlen(buff));
NSLog(@"客户端:发送%zd字节消息",sizeLen);
}
三、本地制作服务器编程(测试)
- 1、创建socket
//创建socket
/// int socket(int family, int type, int protocol);
///参数一:family:协议簇或者协议域(AF_INET:IPv4协议;AF_INET6:IPv6协议;AF_LOCAL:Unix域协议;AF_ROUTE:路由套接字;AF_KEY:密钥套接字)
///参数二:type:套接字类型(SOCK_STREAM:字节流套接字;SOCK_DGRAM:数据包套接字;SOCK_EQPACKET:有序分组套接字;SOCK_RAW:原始套接字)
///参数三:protocol协议类型(IPPROTO_TCP:TCP传输协议;IPPROTO_UDP:UDP传输协议;IPPROTO_SCTP:SCTP传输协议;0:选择所给定family和type组合的系统默认值)
self.serverId = socket(AF_INET, SOCK_STREAM, 0);
if(self.serverId == -1){
NSLog(@"服务端:服务端创建socket失败");
return;
}
- 2、绑定socket
//绑定socket
struct sockaddr_in sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(8040);
struct in_addr inAddr;
inAddr.s_addr = inet_addr("127.0.0.1");
sockAddr.sin_addr = inAddr;
bzero(&sockAddr.sin_zero, 8);
///int bind(int, const struct sockaddr *, socklen_t)
///参数一:socket描述符
///参数二:socket地址结构体指针
///参数三:socket地址结构体大小
int bindResult = bind(self.serverId, (const struct sockaddr *)&sockAddr, sizeof(sockAddr));
if(bindResult == -1){
NSLog(@"服务端:socket 绑定失败");
return;
}
- 3、监听socket
//监听socket
///int listen(int, int)
///参数一:socket标识符
///参数二:最大连接数
int lisentResult = listen(self.serverId, kMaxConnectCount);
if(lisentResult == -1){
NSLog(@"服务端:监听失败");
return;
}
- 4、接收消息
///接受信息
dispatch_async(dispatch_get_global_queue(0, 0), ^{
struct sockaddr_in client_address;
socklen_t socklen;
///int accept(int, struct sockaddr * __restrict, socklen_t * __restrict)
///参数一:socket描述符
///参数二:socket地址结构体指针
///参数三:socket地址结构体大小
int client_socket = accept(self.serverId, (struct sockaddr *)&client_address, &socklen);
self.clientSocket = client_socket;
if(client_socket == -1){
NSLog(@"服务端:接受客户端连接错误");
}else{
NSString *acceptInfo = [NSString stringWithFormat:@"客户端 in,socket:%d",client_socket];
NSLog(@"服务端:%@",acceptInfo);
[self recvMsg:client_socket];
}
});
///接受信息
- (void)recvMsg:(int)clientSocket{
while (1) {
char buff[1024] = {0};
ssize_t sizeLen = recv(clientSocket, buff, 1024, 0);
if(sizeLen>0){
NSLog(@"服务端:客户端来消息了");
NSData *recvData = [NSData dataWithBytes:buff length:sizeLen];
NSString *recvStr = [[NSString alloc] initWithData:recvData encoding:NSUTF8StringEncoding];
NSLog(@"服务端:%@",recvStr);
}else if (sizeLen == -1){
NSLog(@"服务端:读取数据失败");
break;
}else if (sizeLen == 0){
NSLog(@"服务端:客户端走了");
close(clientSocket);
break;
}
}
}
- 5、发送消息
///发送信息
- (void)sendMsg:(NSString *)msg{
size_t sendResult = write(self.clientSocket, msg.UTF8String, strlen(msg.UTF8String));
NSLog(@"服务端:发送%zu字节数据",sendResult);
}
- 6、关闭连接
///关闭连接
- (void)close:(int)clientSocket{
int closeResult = close(clientSocket);
if(closeResult == -1){
NSLog(@"服务端:关闭失败");
return;
}else{
NSLog(@"服务端:关闭成功");
}
}
四、操作步骤
-
1、效果图
-
2、模拟器运行->点击服务端开始socket->点击客户端连接socket,连接成功后即可开始通信
- demo连接:https://github.com/dennie-lee/SocketDemo
- 如有错误理解,请各路大佬批评指出
- 转载请标明出处
- 有空会不定时发表新文章的哦