Zzangg  

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

image

代码:

timeserver:

点击查看代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <time.h>
#include <pthread.h>

#define MAX 256
#define SERVER_HOST "localhost"
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 13312

struct sockaddr_in server_addr, client_addr;
int mysock, csock; // socket descriptors
int r, len, n;     // help variables
time_t nowtime;

int server_init()
{
    printf("================== server init ======================\n");

    // create a TCP socket by socket() syscall
    printf("1 : create a TCP STREAM socket\n");
    mysock = socket(AF_INET, SOCK_STREAM, 0);

    if (mysock < 0)
    {
        printf("socket call failed\n");
        exit(1);
    }
    printf("2 : fill server_addr with host IP and PORT info\n");
    // initialize the server_addr structure
    server_addr.sin_family = AF_INET;                // for TCP/IP
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // This HOST IP
    server_addr.sin_port = htons(SERVER_PORT);       // port number 1234
    printf("3 : bind socket to server address\n");
    r = bind(mysock, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (r < 0)
    {
        printf("bind failed\n");
        exit(3);
    }
    printf(" hostname = %s port = %d\n", SERVER_HOST, SERVER_PORT);
    printf("4 : server is listening ....\n");
    listen(mysock, 5); // queue length = 5
    printf("=================== init done =======================\n");
}

static void Data_handle(void *sock_fd)
{
    int fd = *((int *)sock_fd);
    char buff[MAX];
    while (1)
    {   
        
        nowtime = time(NULL);
        printf("%s", ctime(&nowtime));
        sprintf(buff, "客户端IP: 127.0.0.1 \n 服务器实现者学号:20191312\n当前时间: %s", ctime(&nowtime));
        write(csock, buff, MAX);
        printf("server: ready for next request\n");
        sleep(2);
    }


    //Clear
    printf("terminating current client_connection...\n");
    close(fd);          //close a file descriptor.
    pthread_exit(NULL); //terminate calling thread!
}

int main()
{
    char line[MAX];
    pthread_t thread_id;
    server_init();
    while (1)
    { // Try to accept a client request
        printf("server: accepting new connection ....\n");
        // Try to accept a client connection as descriptor newsock
        len = sizeof(client_addr);
        csock = accept(mysock, (struct sockaddr *)&client_addr, &len);
        if (csock < 0)
        {
            printf("server: accept error\n");
            exit(1);
        }
        printf("server: accepted a client connection from\n");
        printf("---------------------------------------------–\n");
        printf("Clinet: IP=%s port=%d\n",
               inet_ntoa(client_addr.sin_addr),
               ntohs(client_addr.sin_port));
        printf("---------------------------------------------–\n");

        // Processing loop: client_sock <== data ==> client
        if (pthread_create(&thread_id, NULL, (void *)(&Data_handle), (void *)(&csock)) == -1)
        {
            fprintf(stderr, "pthread_create error!\n");
            break; //break while loop
        }
    }
}

timeclient:

点击查看代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

#define MAX 256
#define SERVER_HOST "localhost"
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 13312
struct sockaddr_in server_addr;
int sock, r;
int client_init()
{
    printf("======= clinet init ==========\n");
    printf("1 : create a TCP socket\n");
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        printf("socket call failed\n");
        exit(1);
    }
    printf("2 : fill server_addr with server’s IP and PORT\n");
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); // localhost
    server_addr.sin_port = htons(SERVER_PORT);          // server port number
    printf("3 : connecting to server ....\n");
    r = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (r < 0)
    {
        printf("connect failed\n");
        exit(3);
    }
    printf("4 : connected OK to\n");
    printf("-------------------------------------------------------\n");
    printf("Server hostname=%s PORT=%d\n", SERVER_HOST, SERVER_PORT);
    printf("-------------------------------------------------------\n");
    printf("========= init done ==========\n");
}
int main()
{
    int n;
    char line[MAX], ans[MAX];
    client_init();
    printf("******** processing loop *********\n");
    while (1)
    {
        // Read a line from sock and show it
        read(sock, ans, MAX);
        printf("%s", ans);
    }
}

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

image

image

echoserver:

点击查看代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include <time.h>

#define MAXCONN 2
#define ERRORCODE -1
#define BUFFSIZE 1024
int count_connect = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
struct pthread_socket
{
	int socket_d;
	pthread_t thrd;
};

struct sockaddr_in sockaddr; //定义IP地址结构

struct sockaddr_in accept_sockaddr; //定义accept IP地址结构
socklen_t addrlen = sizeof(accept_sockaddr);

static void* thread_recv(void *arg1)
{
	char buf[BUFFSIZE];
	struct pthread_socket *pt = (struct pthread_socket *) arg1;
	int sd = pt->socket_d;
	pthread_t thrd = pt->thrd;
    time_t clock;
    time(&clock);
	while (1)
	{
		memset(buf, 0, sizeof(buf));
		int rv = recv(sd, buf, sizeof(buf), 0); //是阻塞的
		if (rv < 0)
		{
			printf("recv error:%s \n", strerror(errno));
			break;
        }
        if (rv == 0) // 这种情况说明client已经关闭socket连接
        {
            break;
        }
        printf("echo服务器端接受来自客户端 %s 的内容:%s",inet_ntoa(accept_sockaddr.sin_addr), buf); //输出接受到内容
            char buf1[BUFFSIZE];
            sprintf(buf1,"姓名:20201311陈子昂 echo服务器进程PID:%d  消息:%s\n当前时间:%s",getpid(),buf,ctime(&clock));
        send(sd, buf1, strlen(buf1), 0);
    }
    	pthread_cancel(thrd);
    	pthread_mutex_lock(&mutex);
    	count_connect--;
    	pthread_mutex_unlock(&mutex);
    	close(sd);
    	return NULL;
}
 
static int create_listen(int port)
{
 
    	int listen_st;
    	
    	int on = 1;
    	listen_st = socket(AF_INET, SOCK_STREAM, 0); //初始化socket
    	if (listen_st == -1)
    	{
        	printf("socket create error:%s \n", strerror(errno));
        	return ERRORCODE;
    	}
    	if (setsockopt(listen_st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) //设置ip地址可重用
    	{
        	printf("setsockopt error:%s \n", strerror(errno));
        	return ERRORCODE;
    	}
    	sockaddr.sin_port = htons(port); //指定一个端口号并将hosts字节型传化成Inet型字节型(大端或或者小端问题)
    	sockaddr.sin_family = AF_INET;    //设置结构类型为TCP/IP
    	sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);    //服务端是等待别人来连,不需要找谁的ip
    	//这里写一个长量INADDR_ANY表示server上所有ip,这个一个server可能有多个ip地址,因为可能有多块网卡
    	if (bind(listen_st, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) == -1)
    	{
       		printf("bind error:%s \n", strerror(errno));
        	return ERRORCODE;
    	}
 
    	if (listen(listen_st, 5) == -1) //     服务端开始监听
    	{
        	printf("listen error:%s \n", strerror(errno));
        	return ERRORCODE;
    	}
    	return listen_st;
}
int run_server(int port)
{
    	int listen_st = create_listen(port);    //创建监听socket
    	pthread_t send_thrd, recv_thrd;
    	struct pthread_socket ps;
    	int accept_st;
    	memset(&accept_sockaddr, 0, addrlen);

    	if (listen_st == -1)
    	{
        	return ERRORCODE;
    	}
    	printf("server start \n");
      
	    
    	while (1)
    	{
        	
    	    accept_st = accept(listen_st, (struct sockaddr*) &accept_sockaddr,&addrlen);
    	    //accept 会阻塞直到客户端连接连过来 服务端这个socket只负责listen 是不是有客服端连接过来了
    	    //是通过accept返回socket通信的
    	    if (accept_st == -1)
    	    {
        	    printf("accept error:%s \n", strerror(errno));
        	    return ERRORCODE;
    	    }
            send(*(int *) &accept_st, "hello,welcome to you! \n", strlen("hello,welcome to you! \n"), 0);

        	if (count_connect >= MAXCONN)
        	{
            		printf("connect have already be full! \n");
            		close(accept_st);
            		continue;
        	}
        	pthread_mutex_lock(&mutex);
        	count_connect++;
        	pthread_mutex_unlock(&mutex);
            ps.socket_d = accept_st;
        	if (pthread_create(&recv_thrd, NULL, thread_recv, &ps) != 0)//创建接收信息线程
        	{
            		printf("create thread error:%s \n", strerror(errno));
            		break;
        	}
        	pthread_detach(recv_thrd); //设置线程为可分离,这样的话,就不用pthread_join
    	}
    close(accept_st);
    close(listen_st);
    return 0;
}
//server main
int main(int argc, char *argv[])
{
    	if (argc < 2)
    	{
        	printf("Usage:port,example:8080 \n");
        	return -1;
    	}
    	int port = atoi(argv[1]);
    	if (port == 0)
    	{
        	printf("port error! \n");
    	} 
	else
    	{
        	run_server(port);
    	}
    return 0;
}

echoclient:

点击查看代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
 
#define BUFFSIZE 1024
#define ERRORCODE -1
 
static void *thread_send(void *arg)
{
	char buf[BUFFSIZE];
	int sd = *(int *) arg;
	while (1)
	{
		memset(buf, 0, sizeof(buf));
        //printf("客户端向服务器端发送内容:");
        
		read(STDIN_FILENO, buf, sizeof(buf));
		if (send(sd, buf, strlen(buf), 0) == -1)
		{
			printf("send error:%s \n", strerror(errno));
			break;
		}
	}
	return NULL;
}
static void *thread_recv(void *arg)
{
	char buf[BUFFSIZE];
	int sd = *(int *) arg;
	while (1)
	{
		memset(buf, 0, sizeof(buf));
		int rv = recv(sd, buf, sizeof(buf), 0);
		if (rv <= 0)
		{
			if(rv == 0) //server socket关闭情况
			{
				printf("server have already full !\n");
				exit(0);//退出整个客服端
			}
		    printf("recv error:%s \n", strerror(errno));
		    break;
		}
		printf("\n客户端受到来自服务器端发送的内容:\n%s", buf);//输出接收到的内容
	}	
	return NULL;
}
int run_client(char *ip_str, int port)
{
	int client_sd;
	int con_rv;
	pthread_t thrd1, thrd2;
	struct sockaddr_in client_sockaddr; //定义IP地址结构
	client_sd = socket(AF_INET, SOCK_STREAM, 0);
	if (client_sd == -1)
	{
		printf("socket create error:%s \n", strerror(errno));
		return ERRORCODE;
	}
	memset(&client_sockaddr, 0, sizeof(client_sockaddr));
	client_sockaddr.sin_port = htons(port); //指定一个端口号并将hosts字节型传化成Inet型字节型(大端或或者小端问题)
	client_sockaddr.sin_family = AF_INET; //设置结构类型为TCP/IP
	client_sockaddr.sin_addr.s_addr = inet_addr(ip_str);//将字符串的ip地址转换成int型,客服端要连接的ip地址
	con_rv = connect(client_sd, (struct sockaddr*) &client_sockaddr,
	sizeof(client_sockaddr));
	//调用connect连接到指定的ip地址和端口号,建立连接后通过socket描述符通信
	if (con_rv == -1)
	{
		printf("connect error:%s \n", strerror(errno));
		return ERRORCODE;
	}
	if (pthread_create(&thrd1, NULL, thread_send, &client_sd) != 0)
	{
		printf("thread error:%s \n", strerror(errno));
		return ERRORCODE;
	}
	if (pthread_create(&thrd2, NULL, thread_recv, &client_sd) != 0)
	{
		printf("thread error:%s \n", strerror(errno));
		return ERRORCODE;
	}
	pthread_join(thrd2, NULL);// 等待线程退出
	pthread_join(thrd1, NULL);
	close(client_sd);
	return 0;
}
int main(int argc, char *argv[])
{
	if (argc < 3)
	{
		printf("Usage:ip port,example:127.0.0.1 8080 \n");
		return ERRORCODE;
	}
	int port = atoi(argv[2]);
	char *ip_str = argv[1];
	run_client(ip_str,port);
	return 0;
}

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

华为云服务器:

image

开放全部端口:image

ping通华为云服务器:
image

成功实现:
image

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

image

多进程server:

点击查看代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<pthread.h>
 //20191223
void* communication(void* arg);
 
int main()
{
	int sockfd=socket(PF_INET,SOCK_STREAM,0);
	assert(-1!=sockfd);
 
	struct sockaddr_in ser,cli;
	ser.sin_family=AF_INET;
	ser.sin_port=htons(6000);
	ser.sin_addr.s_addr=inet_addr("127.0.0.1");
	int res=bind(sockfd,(struct sockaddr*)&ser,sizeof(ser));
	assert(-1!=res);
 
	listen(sockfd,5);
 
	while(1)//保证服务器可以连接多个客户端
	{
		int len=sizeof(cli);
		int c=accept(sockfd,(struct sockaddr*)&cli,&len);
        if(c<0)
        {
            printf("link error\n");
            continue;
        }
 
		pthread_t id;
		int n=pthread_create(&id,NULL,communication,(void*)c);//创建线程,将文件描述符强转为void*,此处只能是值传递,地址传递的话,可能函数线程还没拿到该地址的值,就被主线程更改
		assert(n==0);
	}
    close(sockfd);
}
 
void* communication(void* arg)//函数线程完成与客户端的交互
{
	while(1)//实现与一个客户端的多次交互
	{
	    char buff[128]={0};
	    int c=(int)arg;//将文件描述符转回int型
	    int n=recv(c,buff,127,0);
	    if(n<=0)
	    {
			close(c);
			printf("%d client over\n",c);
			break;
	    }
	    printf("%d:%s\n",c,buff);
 
		send(c,"OK",2,0);
	}
}

多进程client:

点击查看代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
 //20201311
int main()
{
	int sockfd = socket(PF_INET,SOCK_STREAM,0);
	assert(-1!=sockfd);
 
	struct sockaddr_in ser,cli;
	memset(&ser,0,sizeof(ser));
	ser.sin_family=AF_INET;
	ser.sin_port=htons(6000);
	ser.sin_addr.s_addr=inet_addr("127.0.0.1");
	int res=connect(sockfd,(struct sockaddr*)&ser,sizeof(ser));
	assert(res!=-1);
 
	while(1)
	{
		printf("Please input:");
		fflush(stdout);
		char buff[128]={0};
		fgets(buff,127,stdin);
		buff[strlen(buff)-1]=0;
 
		if(strncmp(buff,"end",3)==0)
		{
		    break;
		}
		send(sockfd,buff,strlen(buff),0);
 
		memset(buff,0,sizeof(buff));
		recv(sockfd,buff,127,0);
		printf("%s\n",buff);
	}
	close(sockfd);
}
posted on 2022-11-30 16:15  Zzangg  阅读(32)  评论(0编辑  收藏  举报