目的
运用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
#include
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
#include
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
#include
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
connect()从client端连接到server端
listen(),accept()
int listen(int sockfd, int backlog);
-----------------------------------------------------------------
#include
#include
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
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#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
参考
GeeksforGeeks
Beej's Guide to Network Programming 简体中文版