C操作Socket
Socket
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一端称为一个socket。socket也就是套接字,可以用来实现不同虚拟机或者不同计算机之间的通信。在Java语言中,socket可以分为两种类型:面向连接的socket通信协议(TCP)和面向无连接的socket通信协议(UDP)。任何一个socket都是用IP地址与端口号唯一确定的
首先,服务器端Listen(监听)指定的某个端口是否有连接请求;其次,客户端想服务器端发出Connect(连接)请求;最后,服务器端向客户端返回Accept(接受)消息。一个连接就建立起来了,回话随即产生。服务器端与客户端都可以通过Send,Write等方法与对方通信。
笔记
Socket的read及相应的函数及参数:
https://blog.csdn.net/qq_41742289/article/details/104481328?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
socket()函数的参数详解:
https://blog.csdn.net/csdn_kou/article/details/81453573?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159287925219195265948482%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159287925219195265948482&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-81453573.first_rank_ecpm_v1_pc_rank_v3&utm_term=socket%28%29%E5%8F%82%E6%95%B0
源码分析
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
typedef struct recvdata
{
uint16_t type;
uint16_t length;
}RECVDATA;
int select_job(char buffer[256]){
/*
流程分析:
1、创建socket套接字
2、填充sockaddr_in结构体内容(包括地址族、端口号、地址)
2.1、其中地址族有AF_UNIX(本机通信)AF_INET(TCP/IP – IPv4)AF_INET6(TCP/IP – IPv6)
2.2、端口号需要用到htons()函数,此函数是将字节顺序变成大端对齐
2.3、地址用到了inet_addr()函数,此函数是将一个点分十进制的IP转换成一个长整数型数
3、connect()
4、send()
5、read()
6、close()
*/
//创建套接字 这相当于文件套接字FILE,用来标识这次Socket链接
int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服务器(特定的IP和端口)发起请求
/*
sockaddr_in的结构体:
//地址族
short int sin_family;
//端口号(使用网络字节序)
unsigned short int sin_port;
//地址
struct in_addr sin_addr;
//8字节数组,全为0,该字节数组的作用只是为了让两种数据结构大小相同而保留的空字节
unsigned char sin_zero[8]
*/
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址 inet_addr()的功能是将一个点分十进制的IP转换成一个长整数型数
serv_addr.sin_port = htons(21079); //端口 htons是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处 大端对齐?
//通过 connect() 向服务器发起请求,服务器的IP地址和端口号保存在 sockaddr_in 结构体中。直到服务器传回数据后,connect() 才运行结束。
/*
int connect(int sockfd, const struct sockaddr* server_addr, socklen_t addrlen)
返回:0──成功, -1──失败。
参数:
sockfd:socket套接字 解决从哪里发送的问题
server_addr:指定数据发送的目的地,也就是服务器端的地址
addrlen:server_addr的长度
*/
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//使用send函数发送TLV格式数据后
//uint_16代表着2字节无符号整数 unsigned short
uint16_t type = 0x1001;
uint16_t length = 0x0;
uint8_t buf[16];
//memcpy内存拷贝函数,将type内容复制两个字节数给buf
memcpy(buf,&type,2);
memcpy(buf + 2,&length,2);
//printf("buf:%s\n",buf);
RECVDATA senddata;
senddata.type = 0x1001;
senddata.length = 0x0;
/*
int send(SOCKET sock, const char *buf, int len, int flags);
sock 为要发送数据的套接字,buf 为要发送的数据的缓冲区地址,len 为要发送的数据的字节数,flags 为发送数据时的选项一般为0。
*/
send(sock, &senddata, sizeof(RECVDATA),0);
//send(sock, buf, sizeof(buf),0);
uint16_t ret_len = 0; //无符号两个字节的整型
//读取服务器传回的数据
//char buffer[256];
//通过 read() 从套接字文件中读取数据。
//read() 函数会从 fd 文件中读取 nbytes 个字节并保存到缓冲区 buf,成功则返回读取到的字节数(但遇到文件结尾则返回0),失败则返回 -1。
read(sock, &ret_len,2);
//printf("Type form server: %02x\n", ret_len);
read(sock, &ret_len,2);
//printf("Length form server: %02x\n", ret_len);
//read(sock, &recvdata,sizeof(RECVDATA));
//printf("type form server: %02X\n", recvdata.type);
//printf("length form server: %02X\n", recvdata.length);
read(sock, buffer,256);
//printf("Value form server: %s\n", buffer);
//关闭套接字
close(sock);
return 0;
}
char* read_job_json(int flag){
char str[256];
sprintf(str,"/usr/local/www/data/jobs/%d/job.json",flag);//拼出字符串
FILE *f;
if((f=fopen(str,"r+")) == NULL ){
printf("Fail to open file!\n");
exit(0); //退出程序(结束程序)
}
int len;
char *content;
fseek(f,0,SEEK_END);
len=ftell(f);
fseek(f,0,SEEK_SET);
content=(char*)malloc(len+1);
fread(content,1,len,f);
fclose(f);
return content;
}
其中
所以前两个read()读取的是type 和length
上面代码写的是
CGI程序作为TCP Client,在需要的时候,建立到Server的TCP连接,发送命令并接收结果,使用结束后,客户端主动关闭链接。
TCP Client
1,建立socket套接字
2,connect连接服务器套接字(指定服务器ip和端口号)
3,收发数据
4,关闭套接字
具体函数内容的解读看上面的博客中,然后我还淘到一篇讲
read()函数的,说道read函数存在读取不完全的情况: