做了一个向中间件发送字符指令的应用,本着实用的原则,socket的基本原理我只用一张图代替.socket的使用我将以四中形式展现,
首先要知道的:socket传输 分为输入流也叫写入流(针对于客户端而言的,来源于服务器端
),输出流(从客户端输出,发送至服务器端
)
客户端
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXRCVLEN 500
#define PORTNUM 2348
int main(int argc, char *argv[])
{
char buffer[] = "My name is khan"; /* +1 so we can add null terminator */
int len, mysocket;
struct sockaddr_in dest;
mysocket = socket(AF_INET, SOCK_STREAM, 0);
memset(&dest, 0, sizeof(dest)); /* zero the struct */
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1"); /* set destination IP number */
dest.sin_port = htons(PORTNUM); /* set destination port number */
connect(mysocket, (struct sockaddr *)&dest, sizeof(struct sockaddr));
len = send(mysocket, buffer, strlen(buffer), 0);
perror("len\n");
/* We have to null terminate the received data ourselves */
buffer[len] = '\0';
printf("sent %s (%d bytes).\n", buffer, len);
close(mysocket);
return EXIT_SUCCESS;
}
服务器端
#include
#include
#include
#include
#include
#include
#include
#include
#define PORTNUM 2348
#define bufferLength 500
int main(int argc, char *argv[])
{
char buffer[bufferLength];
struct sockaddr_in dest; /* socket info about the machine connecting to us */
struct sockaddr_in serv; /* socket info about our server */
int mysocket; /* socket used to listen for incoming connections */
socklen_t socksize = sizeof(struct sockaddr_in);
memset(&serv, 0, sizeof(serv)); /* zero the struct before filling the fields */
serv.sin_family = AF_INET; /* set the type of connection to TCP/IP */
serv.sin_addr.s_addr = htonl(INADDR_ANY); /* set our address to any interface */
serv.sin_port = htons(PORTNUM); /* set the server port number */
mysocket = socket(AF_INET, SOCK_STREAM, 0);
/* bind serv information to mysocket */
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));
/* start listening, allowing a queue of up to 1 pending connection */
listen(mysocket, 1);
int consocket;
int cpid;
while(1)
{
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
perror("consocket\n");
if( (cpid = fork()) == 0 )
{
printf("inside child process\n\n\n");
close(mysocket);
close(consocket);
int recivedBytes = recv(consocket, buffer, bufferLength, 0);
buffer[recivedBytes] = '\0';
printf("recieved data %s \n", buffer);
return 0;
}
else
close(consocket);
}
close(mysocket);
return EXIT_SUCCESS;
}
1.创建一个线程加入事件
NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"%@:%d", HOST, PORT]];
NSThread * backgroundThread = [[NSThread alloc] initWithTarget:self selector:@selector(loadDataFromServerWithURL:) object:url];
[backgroundThread start];
2.从发送到响应接受服务器返回数据数据
-(void)loadDataFromServerWithURL:(NSURL*)url{
NSString * host = [url host];
NSInteger port = [[url port] integerValue];
//创建Client
CFStreamClientContext ctx = {0, (__bridge void *)(self), NULL, NULL, NULL};
//注册回调事件 触发的时机 具体时机在下面的回调函数中一一介绍
CFOptionFlags registeredEvents = (kCFStreamEventHasBytesAvailable |kCFStreamEventNone|kCFStreamEventOpenCompleted| kCFStreamEventCanAcceptBytes|kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred);
//创建写入流
CFWriteStreamRef writeStream ;
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)host, (UInt32)port, NULL, &writeStream)
;
//加入runloop
if (CFWriteStreamSetClient( writeStream , registeredEventsTwo, socketCallbackCFWriteStreamRef, &ctx)) {
CFWriteStreamScheduleWithRunLoop( writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
}else{
[self networkFailedWithErrorMessage:@"CFWriteStreamSetClient Failed to assign callback method"];
return;
}
//开启写入流
if (CFWriteStreamOpen( writeStream) == NO) {
[self networkFailedWithErrorMessage:@"Failed to open write stream"];
return;
}
CFErrorRef error2 = CFWriteStreamCopyError(writeStream);
if (error2 != NULL) {
if (CFErrorGetCode(error2) != 0) {
NSString * errorInfo = [NSString stringWithFormat:@"Failed to connect stream; error2 '%@' (code %ld)", (__bridge NSString*)CFErrorGetDomain(error2), CFErrorGetCode(error2)];
[self networkFailedWithErrorMessage:errorInfo];
}
//释放
CFRelease(error2);
}
// 开启进程
CFRunLoopRun();
}
void socketCallbackCFWriteStreamRef(CFWriteStreamRef stream, CFStreamEventType event, void * myPtr)
{
NSLog(@"socketCallbackCFWriteStreamRef >> in Thread %@", [NSThread currentThread]);
StreamViewController * controller = (__bridge StreamViewController *)myPtr;
switch(event) {
//开启流
case kCFStreamEventOpenCompleted:
break;
//数据流可以接受数据,在这里你要把你的数据发送到服务器
case kCFStreamEventCanAcceptBytes:{
NSString *testString = @"168353b1-6b6c-4ebd-891e-0b51d81be166|1|f4c1b518-80fe-47aa-8f87-58b5a062dcb9";
NSData *testData = [testString dataUsingEncoding: NSUTF8StringEncoding];
Byte *testByte = (Byte *)[testData bytes];
CFWriteStreamWrite( stream, testByte, testData.length);
}
break;
//发生意外调用,比如你发送了数据给服务器,服务器返回数据在这里读取
case kCFStreamEventErrorOccurred: {
[controller networkFailedWithErrorMessage:@"socketCallbackCFWriteStreamRef 写入失败"];
break;
}
//读取服务器数据
case kCFStreamEventHasBytesAvailable:{
//读取数据,直到无数据返回
while (CFReadStreamHasBytesAvailable(stream)) {
UInt8 buffer[kBufferSize];
int numBytesRead = CFReadStreamRead(stream, buffer, kBufferSize);
[controller didReceiveData:[NSData dataWithBytes:buffer length:numBytesRead]];
}
break;
}
break;
//完成数据接收,关闭流
case kCFStreamEventEndEncountered:
[controller didFinishReceivingData];
// 清理释放内存
CFWriteStreamClose(stream);
CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFRunLoopStop(CFRunLoopGetCurrent());
break;
default:
break;
}
NSStream
是对上面CFReadStreamRef或者CFWriteStreamRef的简单的封装.
NSSream
分为输入流(NSOutputStream
:这对于客户端而言的,来源于服务器端),输出流(NSInputStream
:从客户端输出,发送至服务器端)
//输出流
uint8_t * buffer ;
char * str = "168353b1-6b6c-4ebd-891e-0b51d81be166|1|ddef2049-761a-45a0-9e77-ebf684c4b8f0";
NSOutputStream * outputStream = [NSOutputStream outputStreamToBuffer:buffer capacity:sizeof(buffer)];
//配置 HOST PORT 代理NSStreamDelegate
[outputStream setProperty:@"123.123.118.67" forKey:NSStreamSOCKSProxyHostKey];
[outputStream setProperty:@"4521" forKey:NSStreamSOCKSProxyPortKey];
[outputStream setDelegate:self];
//加入普通寻
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
NSLog(@"%@", [outputStream propertyForKey:NSStreamSOCKSProxyHostKey]);
//开启输出流
[outputStream open];
代理回调
#pragma mark -NSStreamDelegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
//这里和前面的十分类似,对比学习即可,此处不再做详细介绍
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(@"NSStreamEventOpenCompleted");
break;
case NSStreamEventHasBytesAvailable:
NSLog(@"NSStreamEventHasBytesAvailable");
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)aStream read:buf maxLength:1024];
if(len) {
[_data appendBytes:(const void *)buf length:len];
// bytesRead is an instance variable of type NSNumber.
} else {
NSLog(@"no buffer!");
}
break;
//写入数据
case NSStreamEventHasSpaceAvailable:
break;
case NSStreamEventErrorOccurred:
break;
case NSStreamEventEndEncountered:
[aStream close];
[aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
aStream = nil; // aStream是一个指针,避免野指针的产生,此处赋空值;
break;
default:
break;
}
}
Socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
//断开连接
if (Socket.isConnected) {
NSLog(@"链接已经断开,重新开启链接");
[Socket disconnect];
}
//连接服务器 当然公司的ip和端口不能对外公布,请更换为自己的
NSError *err = nil;
if (![Socket connectToHost:@"123.155.118.167" onPort:4521 error:&err]) //Asynchronous!
{
//If there was an error, it's likely something like "already connected" or "no delegate set"
NSLog(@"I goofed: %@", err);
return;
}else{
NSLog(@"正在链接");
}
#pragma mark-GCDAsyncSocketDelegate
//成功链接服务器后调用
- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(@"链接成功Cool, I'm connected! That was easy.%@",[NSThread currentThread]);
//在这里发数据给服务器
NSString *testString = @"168353B1-6B6C-4EBD-891E-0B51D81BE166|1|DDEF2049-761A-45A0-9E77-EBF684C4B8F0";
NSString * lowerString =testString.lowercaseString;
NSData *data = [lowerString dataUsingEncoding:NSUTF8StringEncoding];
//发送数据
[Socket writeData:data withTimeout:-1 tag:1];
}
//与服务器断开链接调用
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
NSLog(@"链接断开%@",[NSThread currentThread]);
}
//发送数据后调用
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
NSLog(@"didWriteDataWithTag %@",[NSThread currentThread]);
switch (tag) {
case 1:
NSLog(@"第一个写入请求发出");
//读取服务器返回信息(不调用这个不会回调下面的紧接着的这个方法)
[sock readDataWithTimeout:-1 tag:10 ];
break;
case 2:
NSLog(@"第2个写入请求发出");
break;
default:
NSLog(@"第3个写入请求发出");
break;
}
}
//服务器返回回数据调用
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
NSLog(@"didReadData %@",[NSThread currentThread]);
if (receiveData == nil) {
//如果不存在,则创建一个新的
receiveData = [[NSMutableData alloc] init];
}
while(data){
[receiveData appendData:data];//把接收到的数据添加上
}
[Socket readDataToData:data withTimeout:-1 tag:TAG_MSG];
NSLog(@"data %@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}
//
- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock{
NSLog(@"%s",__func__);
[sock disconnect];
sock = nil;
}
深入浅出Cocoa
本文主要针对于发送数据到服务器,直接读取服务器内容的请参考自行更改
——————————–写入3/21/2017 11:57
转载请注明网址(yanqinglove.xyz
)