Web服务器1-socket编程

基于华为鲲鹏云服务器CentOS中(或Ubuntu),使用Linux Socket实现:

  1. time服务器的客户端服务器,提交程序运行截图
  2. echo服务器的客户端服务器,提交程序运行截图,服务器把客户端传进来的内容加入“服务器进程pid 你的学号 姓名 echo :”返回给客户端
  3. 服务器部署到华为云服务器,客户端用Ubuntu虚拟机。
  4. 要用多线程或者多进程实现,至少连接两个客户端。
  5. 把服务器部署到试验箱。(加分项)

1. time服务器的客户端服务器,提交程序运行截图

查看虚拟机IP地址
image

timeserver.c:

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

#define MAX 256
struct sockaddr_in server_addr, client_addr;
int mysock, csock;
int count, len;
void server_init(char* SERVER_PORT)
{
    printf("初始化TCP服务器\n");
    printf("创建TCP套接字\n");
    mysock = socket(AF_INET, SOCK_STREAM, 0);
    if(mysock < 0)
    {
        printf("调用套接字失败\n");
        exit(1);
    }
    printf("填充套接字\n");
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi(SERVER_PORT));
    printf("绑定socket\n");
    count = bind(mysock,(struct sockaddr*)&server_addr, sizeof(server_addr));
    if(count < 0)
    {
        printf("绑定套接字失败\n");
        exit(3);
    }
    printf("开始监听\n");
    listen(mysock,5);
    printf("初始化结束\n");

}
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        fprintf(stderr,"%s\n","usage: port");
        exit(0);
    }
    server_init(argv[1]);
	printf("等待客户端连接...\n");

	while(1)
	{
		struct sockaddr_in  ;
		len = sizeof(client_addr);
		int csock = accept(mysock,(struct sockaddr*)&client_addr,&len);
		if(csock < 0)
		{
			perror("accept");
			continue;
		}
		pid_t pid = fork();
		if(pid < 0){
                perror( "fork");
                exit(1);
		}
		else if(pid == 0)
		{
		    pid_t pid_s = getpid();
			char buf[MAX], ans[MAX];
            close(mysock);
			while(1)
            {
			    memset(buf, 0 ,MAX);
			    memset(ans, 0 ,MAX);
			    printf("========connect [ip:port] = [%s:%d]========\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
			    time_t *timep = malloc(sizeof(*timep));
			    time(timep);
			    char *s = ctime(timep);
			    strcpy(ans,s);
			    strcat(ans,"type q to quit");
			    printf("%s",ans);
                count = write(csock,ans,MAX);
                printf("echo:%s\nwrote:%dbytes\npid:%d\n",ans,count,pid_s);
				read(csock,buf,MAX);
				if(0 == strcmp("q",buf))
				{
				    printf("客户端pid:%d 关闭, 服务器监听中\n",pid_s);
					close(csock);
					return 0;
				}
			}
		}
		else if(pid > 0)
        {
            close(csock);
        }
	}
}

timeclient.c:

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#define MAX 256

char *SERVER_HOST = "192.168.131.129";
int sock, count;
struct sockaddr_in server_addr;
int client_init(char* SERVER_PORT)
{
    printf("客户端初始化\n");
    printf("创建套接字\n");
    sock = socket(AF_INET, SOCK_STREAM,0);
    printf("填充套接字\n");
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(SERVER_HOST);
    server_addr.sin_port = htons(atoi(SERVER_PORT));

    printf("连接中.......\n");
    count = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(count < 0)
    {
        printf("连接失败\n");
        exit(3);
    }
    printf("连接成功\n");
    printf("初始化完成\n");
}

int main(int argc, char *argv[])
{
    int n;
    if(argc != 2)
    {
        fprintf(stderr,"%s\n","usage: port");
        exit(0);
    }
    char line[MAX], ans[MAX];
    client_init(argv[1]);
    printf("开始会话\n");
    while(1)
    {
        n = read(sock, ans, MAX);
        printf("%s\n",ans);
        bzero(line, MAX);
        fgets(line,MAX,stdin);
        line[strlen(line)-1] = 0;
        n = write(sock, line, MAX);
        if(0 == strcmp("q",line))
            {
                printf("结束会话\n");
                close(sock);
                return 0;
            }
    }
}

image


2. echo服务器的客户端服务器,提交程序运行截图,服务器把客户端传进来的内容加入“服务器进程pid 你的学号 姓名 echo :”返回给客户端

echoserver.c:

#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>                                                                   
#include <arpa/inet.h>
#include <netdb.h>    
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>

#define MAXLINE 200
#define RIO_BUFSIZE 8192

typedef struct{
    int rio_fd;
    int rio_cnt;
    char *rio_bufptr;
    char rio_buf[RIO_BUFSIZE];

}rio_t;

typedef struct sockaddr SA;

typedef struct{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
}tm;


void *thread(void *vargp);

int main(int argc,char **argv){

    int listenfd,*connfdp,port;
    int clientlen;
    struct sockaddr_in clientaddr;
    struct hostent *hp;
    char *haddrp;
    pthread_t tid;

    if(argc != 2){
    
        fprintf(stderr,"usage:%s <port>\n",argv[0]);
        exit(0);
    }

    port = atoi(argv[1]);

    listenfd = open_listenfd(port);
    
    
    while(1){
    
        clientlen = sizeof(clientaddr);

        connfdp =malloc(sizeof(int));
    
        *connfdp = accept(listenfd,(SA *)&clientaddr,&clientlen);


        hp = gethostbyaddr((const char*)&clientaddr.sin_addr.s_addr,
                sizeof(clientaddr.sin_addr.s_addr),AF_INET);

        haddrp = inet_ntoa(clientaddr.sin_addr);

        printf("server connected to %s (%s)\n",hp->h_name,haddrp);

        pthread_create(&tid,NULL,thread,connfdp);

        pthread_join(tid,NULL);
    }
}


void *thread(void *vargp){
    
    time_t lt;
    tm *local;
    char sbuf[MAXLINE];
    char rbuf[MAXLINE];
    int connfd = *((int*)vargp);

    free(vargp);

    pthread_detach(pthread_self());

    recv(connfd,rbuf,MAXLINE,0);
    printf("The massage is :%s\n",rbuf);
    send(connfd,rbuf,MAXLINE,0);

    close(connfd);
    
    return NULL;
}

echoclient.c:

#include <stdio.h>
#include <netinet/in.h>                                                                   
#include <arpa/inet.h>
#include <netdb.h>    
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>

#define RIO_BUFSIZE 8192

typedef struct{
    int rio_fd;
    int rio_cnt;
    char *rio_bufptr;
    char rio_buf[RIO_BUFSIZE];

}rio_t;

#define MAXLINE 200

int main(int argc,char **argv){

    int clientfd,port;
    char *host,buf[MAXLINE];
    char sbuf[MAXLINE];
    char rbuf[MAXLINE];
    rio_t rio;
    char str1[MAXLINE]="服务器进程pid:";
    char str2[MAXLINE]="服务器实现者学号姓名:20191204 李浩鹏";
    
    char str3[MAXLINE]="echo:";

    if(argc!=3){
    
        fprintf(stderr,"usage:%s <host> <port>\n",argv[0]);
        exit(0);
    }
    host = argv[1];
    port = atoi(argv[2]);

    clientfd = open_clientfd(host,port);
  
    while(1){
        scanf("%[^\n]",sbuf);
        send(clientfd,sbuf,MAXLINE,0);

        recv(clientfd,rbuf,MAXLINE,0);

        printf("%s",str1);
        printf("%d\n",getpid());

        printf("%s",str2);
        putchar('\n');

        printf("%s",str3);

        puts(rbuf);
       
        close(clientfd);
       
        exit(0);
    }

}

image


3. 服务器部署到华为云服务器,客户端用Ubuntu虚拟机。

4. 要用多线程或者多进程实现,至少连接两个客户端。

因为我的华为云账号处于欠费状态,我选择连接蒋进同学的虚拟机来代替华为云服务器,同时部署两个客户端来完成多线程任务。
代码使用的是echoserver.c和echoclient.c

要注意,在连接时需要保证两台电脑在同一网段下,在使用vm虚拟机连接时要将网络适配器改为桥接模式

image

这是我开启服务端并创建客户端连接服务端
image

这是蒋进同学创建客户端连接我的服务端
image
这样就既实现了远端连接又实现了多线程


5. 把服务器部署到试验箱。(加分项)

由于没有实验箱,这里使用树莓派进行代替,都是arm64架构
服务器启动
image
客户端启动
image

客户端收到服务器的回复
image

服务器收到客户端的消息
image

posted @ 2022-11-30 16:55  李兴昕  阅读(14)  评论(0编辑  收藏  举报