基于华为鲲鹏云服务器CentOS中(或Ubuntu),使用Linux Socket实现:
- time服务器的客户端服务器,提交程序运行截图
- echo服务器的客户端服务器,提交程序运行截图,服务器把客户端传进来的内容加入“服务器进程pid 你的学号 姓名 echo :”返回给客户端
- 服务器部署到华为云服务器,客户端用Ubuntu虚拟机。
- 要用多线程或者多进程实现,至少连接两个客户端。
- 把服务器部署到试验箱。(加分项)
1. time服务器的客户端服务器,提交程序运行截图
查看虚拟机IP地址
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;
}
}
}
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);
}
}
3. 服务器部署到华为云服务器,客户端用Ubuntu虚拟机。
4. 要用多线程或者多进程实现,至少连接两个客户端。
因为我的华为云账号处于欠费状态,我选择连接蒋进同学的虚拟机来代替华为云服务器,同时部署两个客户端来完成多线程任务。
代码使用的是echoserver.c和echoclient.c
要注意,在连接时需要保证两台电脑在同一网段下,在使用vm虚拟机连接时要将网络适配器改为桥接模式
这是我开启服务端并创建客户端连接服务端
这是蒋进同学创建客户端连接我的服务端
这样就既实现了远端连接又实现了多线程
5. 把服务器部署到试验箱。(加分项)
由于没有实验箱,这里使用树莓派进行代替,都是arm64架构
服务器启动
客户端启动
客户端收到服务器的回复
服务器收到客户端的消息