网络基础知识
网络层级结构
1、物理层
2、数据链路层 链路层/以太网帧协议、ARP
3、网络层 网络层 /IP /ICMP/IGMP
4、传输层 传输层TCP/UDP
5、会话层 应用层/http/https/ft
6、表示层
7、应用层
IP地址:在网络环境中唯一标识一台主机,是一个点分十进制字符串
端口号:在主机中唯一标识一个进程
IP+Port:在网络环境中唯一标识一个进程
1、socket 是成对出现
2、socket 一定需要绑定IP + 端口
3、Linux的socket是一个文件描述符指向两个缓冲区,一个是读,一个是写
网络字节序
-
小端:高位存高地址,地位存低地址 (计算机存储)
-
大端:高位存低地址,地位存高地址 (网络字节序)
-
函数
- htonl() -> 本地->网络 (ip)
- htons() -> 本地-> 网络 (端口)
- ntohl() -> 网络-> 本地 (ip)
- ntohs() -> 网络 -> 本地 (port)
IP地址转换及其相关的socket函数
int inet_pton(int af, const char *src, void *dst); 本地字节序(string ip ) -> 网络字节序 params: af: AF_INET, AF_INET6 src: 传入的IP地址,(点分十进制) dts: 传出,网络字节序 return: 0 , 说明src 指向的不是一个有效的IP地址, 异常 1, 成功 -1, 失败 const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); af: AF_INET, AF_INET6 src: 网络字节序IP地址 dst: 本地字节序(string ip) return: success: dst failed:NULL sockaddr 地址结构: struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htos(8882); int dst; inet_pton(AF_INET, "22.33.22.21", (void*)&dst); //addr.sin_addr.s_addr = dst; addr.sin_addr.s_addr = htol(INADDR_ANY); /*两种写法一样的,但是第二种更加简单*/ /*man 3 ip*/ bind(fd, (struct sockaddr*)&addr, len); listen() 设置监听上限并发 accept() 阻塞监听客户端连接 #include <sys/socket.h> int socket(int domain, int type, int protocol); domain: AF_INET/AF_INET6/AF_UNIX type: SOCKET_STREAM/SOCKET_DGRAM protocol:0 return: 成功:返回fd 失败:返回NULL int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); sockfd: socket 返回的函数值 addr: struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(882); addr.sin_addr.s_addr = htonl(INADDR_ANY); (structr sockaddr *)&addr; len: sizeof(addr) 地址结构的大小 return: 成功:0 失败:-1 // listen int listen(int sockfd, int backlog); 设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量) sockfd: socket 返回值 backlog:上限数值,最大值(128) return: 成功:0 失败:-1 //accept // comment:阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的socket文件描述符 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); sockfd:socket 返回值 addr:传出参数,成功与服务器建立连接的哪个客户端的地址结构 addrlen:传入传出参数,入:addr的大小值,出是客户端的实际大小 socketlen_t client_addr_len = sizeof(addr); return: 成功:能与server通信的客户端的socket文件描述符 失败:-1, errno // connect // comment: //使用现有的socket与server建立连接 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); sockfd:socket 返回值 addr:传入服务器的地址结构 addrlen:传入传出参数,sizeof(addr) return: 成功:0 失败:-1
-
简单的服务端开发流程
客户端实现流程
代码示例:
/*
* @Description: TCP Server 端代码
* @Version: V0.01
* @Author:
* @Date:
* @LastEditors:
* @LastEditTime:
*/
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <iostream>
#include <arpa/inet.h>
void print_error(const char *str) {
perror(str);
exit(1);
}
int main(int argc, char const *argv[])
{
char msg[BUFSIZ];
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
print_error("socket build error");
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8888);
int err = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
listen(server_fd, 128); // 设置并发数为128个连接
socklen_t cli_len;
struct sockaddr_in client_addr;
std::cout << "Server running ..." << std::endl;
int cli_fd = accept(server_fd, (struct sockaddr *)&client_addr, &cli_len);
if(cli_fd == -1) {
print_error("get client accept error");
}
char client_ip[128];
std::cout << "Client ip:" << std::string(inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_ip, sizeof(client_ip))) \
<< " Client port:" << ntohs(client_addr.sin_port) << std::endl;
int msg_len = read(cli_fd, msg, sizeof(msg));
for (int i = 0; i < cli_len; i++) {
msg[i] = toupper(msg[i]);
}
write(cli_fd, msg, msg_len);
close(cli_fd);
close(server_fd);
return 0;
}
/*
* @Description: TCP socket 客户端
* @Version: V0.01
* @Author:
* @Date:
* @LastEditors:
* @LastEditTime:
*/
#include <sys/socket.h>
#include <sys/types.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
// #include <ctype.h>
#include <iostream>
#include <arpa/inet.h>
void print_error(const char * str) {
perror(str);
exit(1);
}
int main(int argc, char const *argv[])
{
char msg_buf[] = "Hello world!";
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in svr_addr;
svr_addr.sin_family = AF_INET;
svr_addr.sin_port = htons(8888);
// inet_
svr_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
int err = connect(client_fd, (struct sockaddr*)&svr_addr, sizeof(svr_addr));
if (err!= 0) {
print_error("connect error");
}
write(STDOUT_FILENO, msg_buf, strlen(msg_buf));
write(client_fd, msg_buf, strlen(msg_buf));
read(client_fd, msg_buf, strlen(msg_buf));
std::cout << std::endl;
write(STDOUT_FILENO, msg_buf, strlen(msg_buf));
close(client_fd);
return 0;
}