目的
运用 TCP 相关原理,实现一个简单的 server 端和 client 端的数据库交互程序,可以将 client 端输入的指令被 server 端解析,将返回信息又返送给 client 端。
之前的简单内存数据库的实现:T-Tree、T*-Tree 的理解与简单内存数据库的实现
TCP/IP,socket 等相关计算机网络原理
七层网络模型
七层网络模型
TCP/IP
TCP/IP 是互联网协议簇的统称。TCP-transmission control protocal- 传输控制协议 IP-Internet Protocal- 因特网协议 UDP 是 User Datagram Protocol 是无连接类型的传输层协议,
socket 是什么
socket 是对 TCP/IP 协议的封装,socket 翻译为套接字,socket 是一个接口 / 插座。TCPIP 是 Socket 的一种实现,Socket 并不只有 TCP/IP。
两种 socket:stream sockets,datagram socket
socket 其实不止两种。stream socket:串流式 socket。是有连接类型的,网页浏览器所使用的 HTTP 协议是用 stream sockets 取得网页。datagram socket:讯息式 socket。是无连接类型的,用于语音通信,视频传输较多。
TCP server
server 端
socket() 函数
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain
一个地址描述。目前仅支持 AF_INET 格式,也就是说 ARPA Internet 地址格式。
type
指定 socket 类型。新套接口的类型描述类型,如 TCP(SOCK_STREAM)和 UDP(SOCK_DGRAM)。常用的 socket 类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET 等等。
protocol
指定协议。套接口所用的协议。如不想指定,可用 0。常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC 等,它们分别对应 TCP 传输协议、UDP 传输协议、STCP 传输协议、TIPC 传输协议。
bind() 函数
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
bind() 将一本地地址与一 socket 捆绑.
sockfd
sockfd 是 socket() 传回的 socket file descriptor。
my_addr
my_addr 是指向包含你的地址资料丶名称及 IP address 的 struct sockaddr 之指针。
addrlen
addrlen 是以 byte 为单位的地址长度。
connect
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
connect() 从 client 端连接到 server 端
listen(),accept()
int listen(int sockfd, int backlog);
—————————————————————–
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
send(),recv()
int send(int sockfd, const void *msg, int len, int flags);
————————————————————
int recv(int sockfd, void *buf, int len, int flags);
send() 会返回实际有送出的 byte 数,可能会少与所要传送的数目。recv() 若返回 0,则说明远端那边已经关闭了你的连接
close()
close(sockfd);
关闭 socket。
一个 tcp server 的示例代码:
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
// Function designed for chat between client and server.
void func(int sockfd)
{
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf(“From client: %s\t To client : “, buff);
bzero(buff, MAX);
n = 0;
// copy server message in the buffer
while ((buff[n++] = getchar()) != ‘\n’)
;
// and send that buffer to client
write(sockfd, buff, sizeof(buff));
// if msg contains “Exit” then server exit and chat ended.
if (strncmp(“exit”, buff, 4) == 0) {
printf(“Server Exit…\n”);
break;
}
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf(“socket creation failed…\n”);
exit(0);
}
else
printf(“Socket successfully created..\n”);
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf(“socket bind failed…\n”);
exit(0);
}
else
printf(“Socket successfully binded..\n”);
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf(“Listen failed…\n”);
exit(0);
}
else
printf(“Server listening..\n”);
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf(“server acccept failed…\n”);
exit(0);
}
else
printf(“server acccept the client…\n”);
// Function for chatting between client and server
func(connfd);
// After chatting close the socket
close(sockfd);
}
client 端
一个 tcp client 的示例代码:
// Write CPP code here
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
void func(int sockfd)
{
char buff[MAX];
int n;
for (;;) {
bzero(buff, sizeof(buff));
printf(“Enter the string : “);
n = 0;
while ((buff[n++] = getchar()) != ‘\n’)
;
write(sockfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
read(sockfd, buff, sizeof(buff));
printf(“From Server : %s”, buff);
if ((strncmp(buff, “exit”, 4)) == 0) {
printf(“Client Exit…\n”);
break;
}
}
}
int main()
{
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf(“socket creation failed…\n”);
exit(0);
}
else
printf(“Socket successfully created..\n”);
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
servaddr.sin_port = htons(PORT);
// connect the client socket to server socket
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
printf(“connection with the server failed…\n”);
exit(0);
}
else
printf(“connected to the server..\n”);
// function for chat
func(sockfd);
// close the socket
close(sockfd);
}
通过 TCP 与简易内存数据库的数据交互
为了让 client 端和 server 中的内存数据库,通信如果 server 端和 client 建立连接之后则进入一个大循环,大循环的退出条件是 client 端发去“EXIT”,client 端随即断开连接。
通过 TCP 和内存数据库通信的所以代码
所有代码都在 github 里:slarsar/ttree_mmdb_tcp_server_client
参考
GeeksforGeeksBeej’s Guide to Network Programming 简体中文版