【网络】TCP服务器的实现

xiaoxiao2021-02-28  94

socket编程基本概念

在TCP/IP协议中,IP地址+端口号标识个唯一的一个进程,“IP地址+端口号”就是socket

在TCP协议中,建立连接需要两个进程各自有一个socket标识符,这两个socket组成的socket pair就标识着唯一的连接

相关概念介绍

网络字节序

首先呢,我们都知道内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件的偏移也有大端和小端之分。

同理,网络数据流其实也有大端和小端之分。

网络数据流的地址这样规定:先发出的数据是低地址,后发出的数据是高地址。

TCP/IP协议规定:网络数据流应采用大端字节序,低地址高字节

socket地址数据类型

用到的相关函数

socket

作用

创建socket套接字

头文件

#include<sys/types.h>

#include<sys/socket.h>

函数原型

int socket(int domain,int type, int protocol);

参数

domain我们一般选择AF_INET,表示IPv4

type表示传输数据的类型,有字节流类型和SOCK_STREAM数据报类型SOCK_DGRAM

protocol表示创建的类型方式,我们此时设置为0

返回值

成功返回对应的文件描述符

错误返回-1

bind

作用

进行服务器的IP地址和端口号的绑定

头文件

#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

函数原型

int bind(int sockfd,const struct sockaddr *addr, socklen_t addrlen);

参数

sockfd是服务器的套接字,就是socket函数的返回值

addr是socket服务器的地址内容

addrlen是传入的协议地址的大小

返回值

成功返回0

错误返回-1

listen

作用

设置套接字为监听的状态

头文件

#include<sys/types.h>

#include<sys/socket.h>

函数原型

int listen(int sockfd,int backlog);

参数

sockfd是要设置的套接字

backlog是服务器的最大等待队列的个数

返回值

成功返回0

错误返回-1

connect

作用

使客户端连接到服务器

头文件

#include<sys/types.h>

#include<sys/socket.h>

函数原型

int connect(int sockfd, const struct sockaddr * addr, socklen_t addrlen);

参数

sockfd表示需要连接到服务器的客户端套接字

addr表示服务器的地址和端口号

addrlen表示的是addr的大小

返回值

成功返回0

错误返回-1

accpet

作用

服务器用来接受连接

头文件

#include<sys/types.h>

#include<sys/socket.h>

函数原型

int accept(int sockfd, struct sockaddr * addr,  socklen_t *addrlen);

参数

sockfd表示需要连接的客户端的套接字

addr是传出参数,用来传出客户端的IP地址和端口号

addrlen标示传出参数的长度

返回值

成功返回0

错误返回-1

TCP服务器的代码实现

普通版本

server.c

#include<stdio.h> #include<sys/socket.h> #include<string.h> #include<sys/types.h> #include<unistd.h> #include<netinet/in.h> #include<stdlib.h> #include<error.h> #define SERV_PORT 9999 #define _BACKLOG_ 10 void Usage() { printf("Usage: [ipaddr]\n"); } int main(int argc,char* argv[]) { if(argc != 2) { Usage(); return -1; } //1、调用socket来打开一个网络通信端口 int sock = socket(AF_INET,SOCK_STREAM,0); if(sock < 0) { perror("socket"); exit(1); } //2、服务器来绑定一个固定的IP地址和端口号 struct sockaddr_in serverSocket;//定义服务端的套接字 struct sockaddr_in clientSocket;//定义客户端的套接字 bzero(&serverSocket,sizeof(serverSocket));//归零初始化 serverSocket.sin_family = AF_INET;//设置地址的类型 serverSocket.sin_addr.s_addr = inet_addr(argv[1]); serverSocket.sin_port = htons(SERV_PORT);//设置端口号,SERV_PORT为自定义的宏,值设置为9999 if(bind(sock,(struct sockaddr*)&serverSocket,sizeof(struct sockaddr_in))< 0)//进行绑定,并进行判断 { perror("bind"); close(sock); exit(2); } //3、进行监听 if(listen(sock,_BACKLOG_)< 0) { perror("listen"); close(sock); exit(3); } printf("绑定和监听成功...请等待连接...\n"); while(1) { //4、接受连接 socklen_t len = 0;//定义长度len int clientSock = accept(sock, (struct sockaddr*)&clientSocket,&len);//接受连接 if(clientSock < 0) { perror("accpet"); exit(4); } char buf[INET_ADDRSTRLEN];//定义缓冲区,用来存放IP字符串 memset(buf,0,sizeof(buf));//初始化为0 while(1) { char tmpBuf[1024];//定义空间来存储收到与发送的消息 ssize_t ret = read(clientSock,tmpBuf,sizeof(tmpBuf));//从客户端套接字中读入数据 if(ret < 0) { perror("read"); exit(5); } tmpBuf[ret] = '\0'; printf("#client :# %s\n",tmpBuf);//打印从客户端读入的数据 printf("#server :# "); memset(tmpBuf,'\0',sizeof(tmpBuf));//将buf空间置零 fgets(tmpBuf,sizeof(tmpBuf),stdin);//读入需要发送的数据 write(clientSock,tmpBuf,strlen(tmpBuf)); printf("请等待...\n"); } } close(sock); return 0; }

client.c

#include<stdio.h> #include<stdlib.h> #include<error.h> #include<unistd.h> #include<sys/types.h> #include<netinet/in.h> #define SERVER_PORT 9999 void Usage() { printf("Usage: [client_ip] [client_port]\n"); } int main(int argc, char* argv[]) { if(argc != 3) { Usage(); return 1; } //调用socket来打开一个网络端口 char buf[1024]; char* client_ip = argv[1]; memset(buf,'\0',sizeof(buf)); int sock = socket(AF_INET,SOCK_STREAM,0); //定义sockaddr_in结构体,并进行初始化 struct sockaddr_in serverSocket; serverSocket.sin_family = AF_INET; serverSocket.sin_addr.s_addr = inet_addr(argv[1]); serverSocket.sin_port = htons(SERVER_PORT); //进行服务器的链接 int ret = connect(sock,(struct sockaddr*)&serverSocket,sizeof(serverSocket)); if(ret < 0) { printf("连接失败...\n"); return 2; } printf("连接成功...\n"); while(1) { printf("#client :# "); fflush(stdin); fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1] = '\0'; if(strcmp(buf,"quit")==0) break; write(sock,buf,sizeof(buf)); printf("请等待服务器响应...\n"); read(sock,buf,sizeof(buf)); printf("#server :# %s",buf); } close(sock); return 0; }

多进程版本

server.c

#include<stdio.h> #include<sys/types.h> #include<stdlib.h> #include<sys/socket.h> #include<netinet/in.h> #include<string.h> void Usage() { printf("Usage: [ipaddr] [port]\n"); exit(1); } int main(int argc,char* argv[]) { if(argc != 3) { Usage(); } int sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd < 0) { perror("sock"); exit(2); } struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(atoi(argv[2])); addr.sin_addr.s_addr = inet_addr(argv[1]); if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) < 0) { perror("bind"); exit(3); } if(listen(sockfd,10) < 0) { perror("listen"); exit(4); } printf("wait connect...\n"); while(1) { struct sockaddr_in saddr; socklen_t straddr = sizeof(saddr); int fd = accept(sockfd,(struct sockaddr *)&saddr,&straddr); printf("accept connect...\n"); if(fd < 0) { continue; } pid_t pid = fork(); if(pid < 0) { perror("fork"); exit(6); } else if(pid > 0) { printf("find a new client... ip : %s ... port : %d\n",inet_ntoa(saddr.sin_addr),ntohs(saddr.sin_port)); char buf[1024]; while(1) { int s = read(fd, buf,sizeof(buf)-1); if(s < 0) { perror("read"); exit(7); } else if(s == 0) { printf("connect quit... ip : %s ... port : %d\n",inet_ntoa(saddr.sin_addr),ntohs(saddr.sin_port)); close(fd); break; } else { buf[s] = '\0'; printf("#client: %s\n",buf); write(fd,buf,strlen(buf)); } } close(fd); wait(pid,NULL,0); } else { continue; } } close(sockfd); return 0; }

client.c

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<netinet/in.h> #include<sys/types.h> #include<string.h> #include<sys/socket.h> void Usage() { printf("Usage: [ipaddr] [port]\n"); exit(1); } int main(int argc,char* argv[]) { if(argc != 3) { Usage(); } //打开一个网络端口 int sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd < 0) { perror("socket"); exit(2); } struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(atoi(argv[2])); addr.sin_addr.s_addr = inet_addr(argv[1]); if(connect(sockfd,(struct sockaddr*)&addr, sizeof(addr))< 0) { perror("connect"); exit(3); } printf("连接成功...\n"); char buf[1024]; while(1) { printf("#client: "); fflush(stdout); int s = read(0,buf,sizeof(buf)-1); if(s <= 0) { perror("read"); exit(4); } else { buf[s-1] = 0; write(sockfd,buf,strlen(buf)); } int ret = read(sockfd,buf,sizeof(buf)-1); if(ret < 0) { perror("read"); exit(5); } else if(ret == 0) { printf("连接已断开...\n"); break; } else { buf[s] = '\0'; printf("#server: %s\n",buf); } } close(sockfd); return 0; }

多线程版本

server.c

#include<stdio.h> #include<stdlib.h> #include<error.h> #include<unistd.h> #include<sys/types.h> #include<netinet/in.h> #include<sys/socket.h> #include<pthread.h> #include<string.h> void Usage() { printf("Usage: [addrip] [port]\n"); exit(1); } int StartUp(char* argv[]) { //创建接口 int sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd < 0) { perror("socket"); exit(2); } //进行绑定 struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(atoi(argv[2])); addr.sin_addr.s_addr = inet_addr(argv[1]); if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0) { perror("bind"); exit(3); } //进行监听 if(listen(sockfd,10) < 0) { perror("listen"); exit(4); } return sockfd; } void* Myhandler(void* arg) { int fd = (int)arg; char buf[1024]; while(1) { ssize_t s = read(fd,buf,sizeof(buf)); if(s < 0)//error { perror("read"); exit(6); } else if(s == 0)//quit { printf("client quit...\n"); close(fd); break; } else//write { buf[s] = 0; printf("#client : %s\n",buf); write(fd,buf,strlen(buf)); } } } int main(int argc,char* argv[]) { if(argc != 3) { Usage(); } int sockfd = StartUp(argv); printf("初始化成功...等待连接...\n"); while(1) { struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); int fd = accept(sockfd,(struct sockaddr*)&addr,&addrlen); if(fd < 0) { continue; } printf("连接成功... ip : %s , port: %d\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port)); pthread_t td; pthread_create(&td,NULL,Myhandler,(void*)fd); pthread_detach(td); } close(sockfd); return 0; }

client.c

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<error.h> #include<pthread.h> #include<string.h> static void Usage() { printf("Usage : [ipaddr] [port]\n"); exit(1); } int StartUp(char* argv[]) { //打开接口 int sockfd = socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(atoi(argv[2])); addr.sin_addr.s_addr = inet_addr(argv[1]); if(connect(sockfd,(struct sockaddr*)&addr,sizeof(addr)) < 0) { perror("connect"); exit(2); } return sockfd; } int main(int argc,char* argv[]) { if(argc != 3) { Usage(); } int sockfd = StartUp(argv); printf("连接成功...\n"); while(1) { printf("#client : "); fflush(stdout); char buf[1024]; ssize_t s = read(0,buf,sizeof(buf)-1); if(s <= 0) { perror("read"); exit(2); } else { buf[s-1] = '\0'; write(sockfd,buf,strlen(buf)); } s = read(sockfd,buf,sizeof(buf)-1); if(s == 0) { printf("server quit...\n"); break; } else if(s < 0) { perror("read"); exit(3); } else { buf[s] = '\0'; printf("#server : %s\n",buf); } } close(sockfd); return 0; }

转载请注明原文地址: https://www.6miu.com/read-33269.html

最新回复(0)