A summary of the actual use of socket

Write in front

I have made an application of sending character instruction to middleware. Based on the practical principle, I only use one diagram to replace the basic principle of socket. I will show the use of socket in the form of four middle schools,

The first thing to know: socket transmission is divided into input stream (also called write stream) and output stream (output from client and send to server)

  • C language
  • BSDSocket
  • NSStream
  • GCDAsyncSocket

C language

client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#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;
}

Server side

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#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;
}

BSDSocket

1. Create a thread join event

NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"%@:%d", HOST, PORT]];
NSThread * backgroundThread = [[NSThread alloc] initWithTarget:self                                                        selector:@selector(loadDataFromServerWithURL:)                                                        object:url];
[backgroundThread start];

2. Data returned from sending to response receiving server

-(void)loadDataFromServerWithURL:(NSURL*)url{

NSString * host = [url host];
NSInteger port = [[url port] integerValue];
//Create Client
CFStreamClientContext ctx = {0, (__bridge void *)(self), NULL, NULL, NULL};
//The specific time to register the trigger time of callback events is described in the following callback functions one by one

CFOptionFlags registeredEvents = (kCFStreamEventHasBytesAvailable |kCFStreamEventNone|kCFStreamEventOpenCompleted| kCFStreamEventCanAcceptBytes|kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred);

//Create write stream
CFWriteStreamRef   writeStream   ;



CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)host, (UInt32)port, NULL, &writeStream)
;
//Join runloop
if (CFWriteStreamSetClient(  writeStream , registeredEventsTwo, socketCallbackCFWriteStreamRef, &ctx)) {
CFWriteStreamScheduleWithRunLoop(  writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);

}else{
[self networkFailedWithErrorMessage:@"CFWriteStreamSetClient Failed to assign callback method"];
return;
}
//Enable write stream
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];
}
//release
CFRelease(error2);

}
// Start process

CFRunLoopRun();
}
void socketCallbackCFWriteStreamRef(CFWriteStreamRef stream, CFStreamEventType event, void * myPtr)
{
NSLog(@"socketCallbackCFWriteStreamRef >> in Thread %@", [NSThread currentThread]);
StreamViewController * controller = (__bridge  StreamViewController *)myPtr;
switch(event) {

//Open flow
case kCFStreamEventOpenCompleted:
break; 
//Data flow can accept data. Here you need to send your data to the server
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;
//In case of an unexpected call, for example, you send data to the server, and the data returned by the server is read here
case kCFStreamEventErrorOccurred: {
[controller networkFailedWithErrorMessage:@"socketCallbackCFWriteStreamRef  Write failed"];
break;
}
//Read server data
case kCFStreamEventHasBytesAvailable:{
//Read data until no data is returned
while (CFReadStreamHasBytesAvailable(stream)) {
UInt8 buffer[kBufferSize];
int numBytesRead = CFReadStreamRead(stream, buffer, kBufferSize);

[controller didReceiveData:[NSData dataWithBytes:buffer length:numBytesRead]];
}

break;
}
break;
//Complete data receiving, close flow
case kCFStreamEventEndEncountered:
[controller didFinishReceivingData];
// Clean up free memory
CFWriteStreamClose(stream);
CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFRunLoopStop(CFRunLoopGetCurrent());
break;
default:
break;
}

NSStream

NSStream is a simple encapsulation of CFReadStreamRef or CFWriteStreamRef above
NSSream is divided into input stream (NSOutputStream: for the client, it comes from the server side) and output stream (NSInputStream: output from the client, send to the server side)

//Output stream
uint8_t * buffer ;
char * str = "168353b1-6b6c-4ebd-891e-0b51d81be166|1|ddef2049-761a-45a0-9e77-ebf684c4b8f0";
NSOutputStream * outputStream = [NSOutputStream outputStreamToBuffer:buffer capacity:sizeof(buffer)];

//Configure HOST PORT agent NSStreamDelegate
[outputStream setProperty:@"123.123.118.67" forKey:NSStreamSOCKSProxyHostKey];
[outputStream setProperty:@"4521" forKey:NSStreamSOCKSProxyPortKey];
[outputStream setDelegate:self];
//Join common search
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
NSLog(@"%@",  [outputStream propertyForKey:NSStreamSOCKSProxyHostKey]);
//Open output stream
[outputStream open];

Proxy callback

#pragma mark -NSStreamDelegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{

//This is very similar to the previous one. You can learn by comparison. I will not introduce it in detail here
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;

//Write data
case NSStreamEventHasSpaceAvailable:

break;
case NSStreamEventErrorOccurred:

break;
case NSStreamEventEndEncountered:

[aStream close];
[aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

aStream = nil; // aStream is a pointer to avoid the generation of wild pointer. Null value is assigned here;
break;

default:
break;
}
}

CocoaAsyncSocket

Create socket

Socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

Link server or middleware (Internet of things device intermediate control)

//Disconnect
if (Socket.isConnected) {
NSLog(@"Link is broken,Reopen link");
[Socket disconnect];
}


//Of course, the company's ip and port can't be publicized. Please replace them with your own
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(@"Linking");
}

Execute proxy method - GCDAsyncSocketDelegate

#pragma mark-GCDAsyncSocketDelegate
//Call after successful link server
- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port
{

NSLog(@"Link succeeded Cool, I'm connected! That was easy.%@",[NSThread currentThread]);
//Send data to the server here
NSString *testString = @"168353B1-6B6C-4EBD-891E-0B51D81BE166|1|DDEF2049-761A-45A0-9E77-EBF684C4B8F0";
NSString * lowerString =testString.lowercaseString;

NSData *data = [lowerString dataUsingEncoding:NSUTF8StringEncoding];
//send data 
[Socket writeData:data withTimeout:-1 tag:1];
}
//Disconnect from server call
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
NSLog(@"Broken link%@",[NSThread currentThread]);
}
//Call after sending data
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
NSLog(@"didWriteDataWithTag %@",[NSThread currentThread]);
switch (tag) {
case 1:
NSLog(@"First write request issued");
//Read the server's return information (do not call this method and do not call the following method)
[sock readDataWithTimeout:-1 tag:10 ];
break;
case 2:
NSLog(@"2nd write request issued");

break;
default:
NSLog(@"3rd write request issued");

break;
}


}
//Server return data call
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
NSLog(@"didReadData %@",[NSThread currentThread]);

if (receiveData == nil) {
//If not, create a new
receiveData = [[NSMutableData alloc] init];
}
while(data){
[receiveData appendData:data];//Add the received data to the
}

[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;
}


reference resources

To understand Cocoa

Write it at the back

This article is mainly for sending data to the server and directly reading the content of the server, please refer to self change

——————————– write 3 / 21 / 2017 11:57

Reprint please indicate the website (yanqinglove.xyz)

Tags: socket C encoding

Posted on Sat, 16 May 2020 10:58:13 -0400 by Quevas