第五冶金建设公司职工大学网站,商业空间展示设计,平陆网站建设,汽车专业科技网站建设Socket通信详解 文章目录Socket通信详解Socket流程介绍函数介绍编程实例Socket流程介绍
socket通信类似于电话通信#xff0c;其服务器基本流程就是 Created with Raphal 2.3.0安装电话socket()分配电话号码bind()连接电话线listen()拿起话筒accept()函数介绍
socket()
其中…Socket通信详解 文章目录Socket通信详解Socket流程介绍函数介绍编程实例Socket流程介绍
socket通信类似于电话通信其服务器基本流程就是
Created with Raphaël 2.3.0安装电话socket()分配电话号码bind()连接电话线listen()拿起话筒accept()函数介绍
socket()
其中socket的函数原型如下所示它的作用就是创建套接字同时规定好该套接字的用途 其中的每个参数的作用如下所示
domain:套接字使用的协议族信息(比如PF_INET就是使用IVP4互联网协议族)
type:套接字数据传输类型信息(比如SOCK_STREAM是指面向连接的套接字类型,TCP就是这个类型)
protocol:计算机通信中使用的协议信息(比如IPV4面向连接类型基本就只有TCP这里就填写IPPROTO_TCP)bind()
其中bind的函数原型如下所示它的作用就是把地址信息分配给套接字上也就是前面socket生成的套接字上。其函数原型如下所示 其中中间的__CONST_SOCKADDR_ARG是个宏继续追踪可以知道是个存储地址信息的结构体如下所示 其中每个参数的作用如下所示:
fd:套接字描述符就是前文socket函数的返回值结构体信息是绑定在这个套接字上的
addr:存储地址信息的指针里面有IP和端口信息。
len:就是第二个参数addr的长度那么addr里面的具体详情又是怎么样的呢即sockaddr的结构体定义如下所示是一个14个字节长度的字符串数组。 为了便于填写我们一般使用sockaddr_in结构体然后进行强制类型转换为sockaddr类型 上图中的name就是sockaddr_in类型sockadr_in结构体类型如下所示: 第一个红框中的变量为sin_family其演变如下所示 对socket_In结构体的变量解析如下
sin_family:地址族比如IPV4就填写AF_INET)
sin_port:填写16位网络端口重点是它是以网络字节序保存所以需要进行转换
sin_addr:填写32为ip地址也以网络字节序保存。
sin_zero:无实际含义为了保持与socket结构体长度一致方便强制类型转换。listen()
其中listen的函数原型如下所示 其参数解析如下
fd:前面两个函数都用到过的套接字描述符
n:表示连接请求队列的长度如果设置为5则队列长度为5表示最多使五个连接请求进入队列accept()
其中accept()的函数原型如下所示 其参数解析如下
fd:服务器的套接字描述符
addr:用来保存发起连接的客户端的地址信息
addr_len:第二个参数的结构体长度当函数调用完成后这个参数就是被填入的客户端地址长度
返回值:一个套接字的文件描述符这个套接字是accept函数生成的用来和这个客户端对话的。编程实例 文件介绍 hello_server.c就是主要的文件也就是实例。hello_client.c是配合服务器测试的客户端程序。Makefile是用来编译两者的。 测试流程 make
./hello_server 9190 //这个端口随便选择一个没有占用的端口即可
./hello_client 127.0.0.1 9190//这里的ip和端口号要与服务器的ip端口号保持一致此时客户端会收到一个消息消息内容为Message from server: hello World! 测试截图 服务端运行 客户端运行以及结果 hello_server.c #include arpa/inet.h
#include stdio.h
#include stdlib.h
#include string.h
#include sys/socket.h
#include unistd.h
void error_handling(char* message);
int main(int argc, char* argv[]) {int serv_sock;int clnt_sock;struct sockaddr_in serv_addr;struct sockaddr_in clnt_addr;socklen_t clnt_addr_size;char message[] hello World!;if (argc ! 2) {printf(Usage : %s port\n, argv[0]);exit(1);}serv_sock socket(PF_INET, SOCK_STREAM, 0);//创建套接字if (serv_sock -1) {error_handling(socket() error);}memset(serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family AF_INET;serv_addr.sin_addr.s_addr htonl(INADDR_ANY);serv_addr.sin_port htons(atoi(argv[1]));if (bind(serv_sock, (struct sockaddr*)serv_addr, sizeof(serv_addr)) -1)//将地址信息绑定套接字error_handling(bind() error);if (listen(serv_sock, 5) -1) error_handling(listen() error);//监听套接字clnt_addr_size sizeof(clnt_addr);clnt_sock accept(serv_sock, (struct sockaddr*)clnt_addr, clnt_addr_size);//当收到客户端消息的时候创建一个套接字来进行通信if (clnt_sock -1) {error_handling(accept() error);}write(clnt_sock, message, sizeof(message));close(clnt_sock);close(serv_sock);return 0;
}
void error_handling(char* message) {fputs(message, stderr);fputc(\n, stderr);exit(1);
}hello_client.c #include arpa/inet.h
#include stdio.h
#include stdlib.h
#include string.h
#include sys/socket.h
#include unistd.h
void error_handling(char* message);
int main(int argc, char* argv[]) {int sock;struct sockaddr_in serv_addr;char message[30];int str_len;if (argc ! 3) {printf(Usage : %s IP port\n, argv[0]);exit(1);}sock socket(PF_INET, SOCK_STREAM, 0);if (sock -1) {error_handling(socket() error);}memset(serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family AF_INET;serv_addr.sin_addr.s_addr inet_addr(argv[1]);serv_addr.sin_port htons(atoi(argv[2]));if (connect(sock, (struct sockaddr*)serv_addr, sizeof(serv_addr)) -1)error_handling(connect() error);str_len read(sock, message, sizeof(message) - 1);if (str_len -1) error_handling(read() error);printf(Message from server: %s \n, message);close(sock);return 0;
}
void error_handling(char* message) {fputs(message, stderr);fputc(\n, stderr);exit(1);
}MakeFile all: server clientserver: hello_server.cclang-format -stylegoogle -i hello_server.cgcc hello_server.c -o hello_server
client: hello_client.cclang-format -stylegoogle -i hello_client.cgcc hello_client.c -o hello_client
clean:rm hello_client hello_server