Experiment 0x4:I/O复用实现并发服务器
0x0 说明
实验四:I/O复用实现并发服务器
客户端跟实验二、实验三一样,服务器通过I/O复用实现并发。
这一节不太理解。。记录一下实验课代码
代码环境:
win10
VS2019 远程连接 ubuntu20
进行linux编程
0x1 要求
要求:实现采用阻塞方式的并发服务网络通信程序,同时包含服务器与客户端。要求完成以下功能:
1、采用了非阻塞式的并发服务器编程模板,设计一个基于TCP协议的网络通信程序;
2、实现并发服务器的功能,服务器完成客户端的非阻塞网络通信。
0x2 实现
实现采用阻塞方式的并发服务网络通信程序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mJiHTEVt-1648638382015)(./picture/实验四.png)]
0x3 源码
1- TCP服务端源码
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#define PORT 9976
#define BACKLOG 5
#define MAXDATASIZE 1000
typedef struct _ {
int fd;
char* name;
struct sockaddr_in addr;
char* data;
}CLIENT;
void savedata(char* recvbuf, int len, char* data)
{
int start = strlen(data);
for (int i = 0; i < len; i++)
data[start + i] = recvbuf[i];
}
void process_cli(CLIENT* client, char* recvbuf, int len)
{
char sendbuf[MAXDATASIZE];
recvbuf[len] = '\x0';
if (strlen(client->name) == 0)
{
memcpy(client->name, recvbuf, len);
return;
}
printf("Received client(%s)message:%s\n", client->name, recvbuf);
savedata(recvbuf, len, client->data);
for (int i1 = 0; i1 < len; i1++)
{
sendbuf[i1] = recvbuf[len - i1 - 1];
}
sendbuf[len] = '\x0';
send(client->fd, sendbuf, strlen(sendbuf), 0);
}
int main(void)
{
int i, maxi, maxfd, sockfd;
int nready;
ssize_t n;
fd_set rset, allset;
int listenfd, connectfd;
struct sockaddr_in server;
CLIENT client[FD_SETSIZE];
char recvbuf[MAXDATASIZE];
int sin_size;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("error.");
exit(1);
}
int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listenfd, (struct sockaddr*)&server, sizeof(server)) == -1)
{
perror("error.");
exit(1);
}
if (listen(listenfd, BACKLOG) == -1)
{
perror("error.");
exit(1);
}
sin_size = sizeof(struct sockaddr_in);
maxfd = listenfd;
maxi = -1;
for (i = 0; i < FD_SETSIZE; i++)
client[i].fd = -1;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
while (1)
{
struct sockaddr_in addr;
rset = allset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (FD_ISSET(listenfd, &rset))
{
if ((connectfd = accept(listenfd, (struct sockaddr*)&addr, (socklen_t*)&sin_size)) == -1)
{
perror("accept error.");
continue;
}
for (i = 0; i < FD_SETSIZE; i++)
if (client[i].fd < 0)
{
client[i].fd = connectfd;
client[i].name = (char*)malloc(MAXDATASIZE);
client[i].addr = addr;
client[i].data = (char*)malloc(MAXDATASIZE);
client[i].name[0] = '\0';
client[i].data[0] = '\0';
printf("You got a connect from %s. ", inet_ntoa(client[i].addr.sin_addr));
break;
}
if (i == FD_SETSIZE) printf("too many cllients.\n");
FD_SET(connectfd, &allset);
if (connectfd > maxfd) maxfd = connectfd;
if (i > maxi) maxi = i;
if (--nready <= 0) continue;
}
for (i = 0; i <= maxi; i++)
{
if ((sockfd = client[i].fd) < 0) continue;
if (FD_ISSET(sockfd, &rset))
{
if ((n = recv(sockfd, recvbuf, MAXDATASIZE, 0)) == 0)
{
close(sockfd);
printf("Client (%s) closed connection. User’s data: %s\n", client[i].name, client[i].data);
FD_CLR(sockfd, &allset);
client[i].fd = -1;
}
else
process_cli(&client[i], recvbuf, n);
if (--nready <= 0) break;
}
}
}
close(listenfd);
}
2- TCP客户端源码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#define PORT 9976
#define MAXDATASIZE 1000
void process(FILE* fp, int sockfd);
char* getMessage(char* sendbuf, int len, FILE* fp);
int main(int argc, char* argv[]) {
int sockfd;
hostent* he;
sockaddr_in server;
if (argc != 2) {
printf("Usage: %s <IP address>\n",argv[0]);
return 0;
}
he = gethostbyname(argv[1]);
if (he == NULL) {
perror("gethostbyname() error: ");
_exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("skcket() error: ");
_exit(1);
}
bzero(&server, sizeof(sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr = *(in_addr*)he->h_addr_list[0];
int flag = connect(sockfd, (sockaddr*)&server, (socklen_t)sizeof(sockaddr_in));
if (flag == -1) {
perror("connect() error: ");
_exit;
}
process(stdin, sockfd);
close(sockfd);
return 0;
}
void process(FILE* fp, int sockfd) {
char sendbuf[MAXDATASIZE] = { 0 };
char recvbuf[MAXDATASIZE] = { 0 };
int num = 0;
printf("Connected to server.\n");
printf("Input client's name (must >= 2 bytes): ");
if (fgets(sendbuf, MAXDATASIZE, fp) == NULL) {
printf("\nExit.\n");
return;
}
if (strlen(sendbuf) < 2) {
printf("Illegal input!\n");
return;
}
send(sockfd, sendbuf, strlen(sendbuf), 0);
memset(sendbuf, 0, MAXDATASIZE);
while (getMessage(sendbuf, MAXDATASIZE, fp) != NULL ) {
send(sockfd, sendbuf, strlen(sendbuf), 0);
num = recv(sockfd, recvbuf, MAXDATASIZE, 0);
if (num == 0) {
printf("Server Terminated.\n");
return;
}
recvbuf[num] = 0;
printf("Server Message:%s\n", recvbuf);
}
printf("\nExit.\n");
close(sockfd);
}
char* getMessage(char* sendbuf, int len, FILE* fp) {
printf("Input string to server: ");
return fgets(sendbuf, MAXDATASIZE, fp);
}
|