ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

厦门大学计算机网络第三次实验

2021-11-22 12:02:13  阅读:186  来源: 互联网

标签:第三次 self send server 计算机网络 msg 厦门大学 recv addr


厦门大学计算机网络第三次实验

准备工作

1.安装本地echo服务,监听7号端口。我使用的是ubuntu虚拟机,修改的文件与centos7略有不同。

image-20211121110032815

可以看到我已经配置好了。(不会配置的可以搜索一下,ubuntu打开echo标准服务)

2.在ubuntu虚拟机编程太难受了,vscode使用ssh连接,在vscode里code和调试。image-20211121111352122

字符串逆序回送(TCP迭代)

1.成果展示:

客户端image-20211121110458104

服务器:image-20211121110551697

第一个客户端正常收发image-20211121110742726

第二个客户端等待

image-20211121110808728

收到bye后,立刻开始处理第二个客户端:

image-20211121110834432

image-20211121110906695

2.具体实现

在服务器端使用双重循环,内部有字符串处理

image-20211121111512073

客户端使用单个循环。

我还在对运行时参数做了处理,这样服务器和客户端就可以自定地址和端口号。

image-20211121111708557

3.为什么ip地址和端口号需要字节顺序转换?

htnol()函数其实很好理解,就是小端装换成大端,因为网络地址是大端,但计算机内存不一定与之一样,所以必须要转换。

字符串逆序回送(TCP并发)

1.先看实现成果

服务器端:image-20211121120639186

两个客户端

image-20211121120826868

image-20211121120836735

2.实验报告要求的三客户端:

image-20211121121803326

3.实现细节

  • 需要在子进程中关掉监听socketimage-20211121122056308
  • 在父进程关闭数据socketimage-20211121122137418
  • 一定要记得清楚僵尸进程image-20211121122203306

4.ppt问题。服务器accept之后会返回一个用于传输数据的socket,调用fork()会使父子进程同时拥有此socket描述符,父进程分支中是否需要关闭该socket?

答案是需要

若不关闭,在退出客户端后,还有多个网络连接在CLOSE_WAITimage-20211121123141693

基于UDP socket的简易聊天室

  1. 首先我了解了线程相关知识。
  • 守护线程:如果有一个线程必须设置为无限循环,那么该线程不结束,意味着整个python程序就不能结束,那为了能够让python程序正常退出,将这类无限循环的线程设置为守护线程,当程序当中仅仅剩下守护线程时,python程序就能够正常退出,不必关心这类线程是否执行完毕,这就是守护线程的意义。

  • 因为客户端需要一边发送,一边接受。就创建一个守护线程来控制接受信息。

  1. 成果图:

    服务器:image-20211122113657501

    客户端,检测用户名登录image-20211122114131574

    客户端,聊天内容image-20211122114237015

    客户端退出:image-20211122114302869

    捕获的异常(服务器突然关闭)image-20211122114437873

  2. 实现:客户端

    1. 创建两个线程,其中设定接受信息为守护线程

    2. image-20211122114603482

    3. 检测昵称

    4. image-20211122114810548

    5. 异常捕获

    6. image-20211122114851196

    7. 实现:服务器

      1. 初始化image-20211122115030316
      2. 接受信息image-20211122115051851
      3. 群发消息image-20211122115110302
      4. mainimage-20211122115135608

源代码

  • server1.c

    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <error.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
    	int server_sock_listen, server_sock_data;
    	struct sockaddr_in server_addr;
    	char recv_msg[255];
    	char send_msg[255];
    	/* 创建socket */
    	server_sock_listen = socket(AF_INET, SOCK_STREAM, 0);
    
    	int i,port=0;    //port
        for (i=0;i< strlen(argv[2]);i++) {
            if(argv[2][i] != 0){
                port = port*10 + argv[2][i] - '0';
            }
        }
    	/* 指定服务器地址 */
    	server_addr.sin_family = AF_INET;
    	server_addr.sin_port = htons(port);
    	if(strcmp(argv[1],"localhost")==0){
    		server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY表示本机所有IP地址
    	}
    	else {
    		server_addr.sin_addr.s_addr = htonl(inet_addr(argv[1]));
    	}
    	memset(&server_addr.sin_zero, 0, sizeof(server_addr.sin_zero)); //零填充
    	/* 绑定socket与地址 */
    	bind(server_sock_listen, (struct sockaddr *)&server_addr, sizeof(server_addr));
    
    	/* 监听socket */
    	listen(server_sock_listen, 0);
    	printf("%s is listening:\n",argv[1]);
    	while(1) {
    		server_sock_data = accept(server_sock_listen, NULL, NULL);
    		printf("Accept.....\n");
    		while(1){
    			/* 接收并显示消息 */
    			memset(recv_msg, 0, sizeof(recv_msg)); //接收数组置零
    			memset(send_msg, 0, sizeof(send_msg));
    			recv(server_sock_data, recv_msg, sizeof(recv_msg), 0);
    			printf("Recv: %s\n", recv_msg);
    			if(strcmp(recv_msg,"bye")==0)
    				break;
    			int len = strlen(recv_msg);
    			for( i = 0;i < len; i++) {
    				send_msg[i] = recv_msg[len - 1 - i];
    			}
    			printf("Send: %s\n", send_msg);
    			/* 发送消息 */
    			send(server_sock_data, send_msg, strlen(send_msg), 0);
    			
    		}	
    			/* 关闭数据socket */
    		close(server_sock_data);
    	}
    	
    	
    	/* 关闭监听socket */
    	close(server_sock_listen);
    
    	return 0;
    }
    
    
  • client1.c

    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <error.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
    	int client_sock;
    	struct sockaddr_in server_addr;
        char send_msg[1000];
    	char recv_msg[255];
    
    	/* 创建socket */
    	client_sock = socket(AF_INET, SOCK_STREAM, 0);
    
    	/* 指定服务器地址 */
        int i,port=0;    //port
        for (i=0;i< strlen(argv[2]);i++) {
            if(argv[2][i] != 0){
                port = port*10 + argv[2][i] - '0';
            }
        }
    	if(!strcmp(argv[1],"localhost")) {  //input is  localhost
    		server_addr.sin_addr.s_addr = inet_addr("192.168.238.128");
    	}
    	else{
    		server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    	}
    	server_addr.sin_family = AF_INET;
    	server_addr.sin_port = htons(port); 
    	memset(server_addr.sin_zero, 0, sizeof(server_addr.sin_zero)); //零填充
    
    	/* 连接服务器 */
    	connect(client_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
    
    
    	/* 发送消息 */
        while(1){
            printf("Myself: ");
            scanf("%s", send_msg);
    	    send(client_sock, send_msg, strlen(send_msg), 0);
    		if (strcmp(send_msg,"bye")==0) {
    			break;
    		}
    	/* 接收并显示消息 */
    	    memset(recv_msg, 0, sizeof(recv_msg)); //接收数组置零
    	    recv(client_sock, recv_msg, sizeof(recv_msg), 0);
    	    printf("Recv: %s\n", recv_msg);
    
        }
    	/* 关闭socket */
    	close(client_sock);
    
    	return 0;
    }
    
    
  • server2.c

    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <error.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <sys/wait.h>
    
    int main(int argc, char *argv[])
    {
    	int server_sock_listen, server_sock_data;
    	struct sockaddr_in server_addr;
    	char recv_msg[255];
    	char send_msg[255];
    	/* 创建socket */
    	server_sock_listen = socket(AF_INET, SOCK_STREAM, 0);
    
    	int i,port=0;    //port
        for (i=0;i< strlen(argv[2]);i++) {
            if(argv[2][i] != 0){
                port = port*10 + argv[2][i] - '0';
            }
        }
    	/* 指定服务器地址 */
    	server_addr.sin_family = AF_INET;
    	server_addr.sin_port = htons(port);
    	if(strcmp(argv[1],"localhost")==0){
    		server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY表示本机所有IP地址
    	}
    	else {
    		server_addr.sin_addr.s_addr = htonl(inet_addr(argv[1]));
    	}
    	memset(&server_addr.sin_zero, 0, sizeof(server_addr.sin_zero)); //零填充
    	/* 绑定socket与地址 */
    	bind(server_sock_listen, (struct sockaddr *)&server_addr, sizeof(server_addr));
    
    	/* 监听socket */
    	listen(server_sock_listen, 0);
    
    	printf("%s is listening:\n",argv[1]);
    	struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        while(1) {
    		server_sock_data = accept(server_sock_listen, (struct sockaddr*)&client_addr, 
                    &client_len);
            signal(SIGCHLD, SIG_IGN);
    		pid_t pid = fork();
            if(pid < 0){
                printf("error in fork!\n");
            }
            else if (pid == 0) {
                close(server_sock_listen);
                while(1){
                    /* 接收并显示消息 */
                    memset(recv_msg, 0, sizeof(recv_msg)); //接收数组置零
                    memset(send_msg, 0, sizeof(send_msg));
                    char ip[64];
                    
                    recv(server_sock_data, recv_msg, sizeof(recv_msg), 0);
                    printf("Recv: %s\n", recv_msg);
                    printf("Accept from %s : %d\n",inet_ntop(AF_INET,
                        &client_addr.sin_addr.s_addr,ip,sizeof(ip)),ntohs(client_addr.sin_port));
                    if(strcmp(recv_msg,"bye")==0)
                    {
                        printf("Close from %s : %d\n",inet_ntop(AF_INET,
                        &client_addr.sin_addr.s_addr,ip,sizeof(ip)),ntohs(client_addr.sin_port));
                        break;
                    }
                    int len = strlen(recv_msg);
                    for( i = 0;i < len; i++) {
                        send_msg[i] = recv_msg[len - 1 - i];
                    }
                    printf("Send: %s\n", send_msg);
                    /* 发送消息 */
                    send(server_sock_data, send_msg, strlen(send_msg), 0);
    		    }
                return 0;	
            }
            else{
                    /* 关闭数据socket */
                close(server_sock_data);
            }
    	}
    	/* 关闭监听socket */
    	close(server_sock_listen);
    
    	return 0;
    }
    
    
  • serverchatroom.py

    from socket import *
    from threading import Thread
    import sys
    
    class Server:
    
        user_info = {}
        _ServerOpen = True
    
        def __init__(self,server_port):
            self.serverPort = server_port
            self.udpSocket = socket(AF_INET,SOCK_DGRAM)
            self.udpSocket.bind(self.serverPort)
            self.thread_recv = Thread(target=self.recv_msg)
            self.thread_send = Thread(target=self.send_msg)
    
        def recv_msg(self):
            while True:
                try:
                    recv_data,dest_ip = self.udpSocket.recvfrom(1024)
                    if not self._ServerOpen:
                        self.udpSocket.sendto('exit'.encode(), dest_ip)
                        name = self.user_info[dest_ip]
                        self.sent_to_all('系统: %s 已退出聊天'%name)
                        while len(self.user_info):
                            recv_data,dest_ip = self.udpSocket.recvfrom(1024)
                            self.udpSocket.sendto('exit'.encode(),dest_ip)
                            name = self.user_info[dest_ip]
                            del self.user_info[dest_ip]
                            self.send_to_all(' 系统:%s已退出聊天'%name)
                        print('服务器已关闭')
                        self.udpSocket.close()
                        break
                    #处理登录名
                    info_list = str(recv_data.decode()).split(' ')
                    if info_list[0] == 'login':
                        if info_list[1] not in self.user_info.values():
                            self.udpSocket.sendto('OK'.encode(),dest_ip)
                            self.send_to_all('系统:%s进入聊天室'%info_list[1])
                            self.user_info[dest_ip] = info_list[1]
                        else:
                            self.udpSocket.sendto('Used name'.encode(), dest_ip)
                    
                    elif info_list[0] == 'exit' :
                        message = '%s 退出了聊天室'%self.user_info[dest_ip]
                        self.send_to_all(message)
                        del self.user_info[dest_ip]
                    else:
                        name = self.user_info[dest_ip]
                        message = name + ': '+ recv_data.decode()
                        self.send_to_all(message)
                except (KeyboardInterrupt,EOFError):
                    print('-------服务器中断--------')
                    break
    
        def send_msg(self):
            while self._ServerOpen:
                try:
                    data_ifno = input()
                    if data_ifno == 'exit':
                        self._ServerOpen = False
                        print('服务器关闭中')
                        self.send_to_all('服务器已关闭请下线')
                        break
                except (KeyboardInterrupt,EOFError):
                    print('------服务器中断--------')
                    break
    
        def start(self):
            print('服务器已启动,ip地址:'+self.serverPort[0]+'端口号:%d' %self.serverPort[1])
            self.thread_recv.start()
            self.thread_send.start()
            self.thread_recv.join()
            self.thread_send.join()
        
        def send_to_all(self,message):
            for i in self.user_info.keys():
                self.udpSocket.sendto(message.encode(),i)
    
    if __name__=='__main__':
        port = int(input('请输入要绑定的端口号'))
        server1 = Server(('192.168.1.101', port))
        server1.start()
    
  • clientchatroom.py

    from socket import *
    from threading import Thread
    from requests.exceptions import ConnectionError, ReadTimeout
    import time
    
    class Client():
    
        def __init__(self,server_post):
        #    self.clientPort = client_post
            self.serverPort = server_post
            self.udpSocket = socket(AF_INET,SOCK_DGRAM)
        #    self.userName = name
            self.thread_recv = Thread(target=self.recvMsg,daemon=True)
            self.thread_send = Thread(target=self.sendMsg)
    
        def start(self):
            name = input('请输入昵称:')
            message = 'login '+name
            self.udpSocket.sendto(message.encode(), self.serverPort)
            while True:
                try:
                    recvData,destIP = self.udpSocket.recvfrom(1024)
                    if recvData.decode() == 'OK':
                        print('欢迎来到聊天室,退出聊天室请输入exit')
                        break
                    else:
                        name = input('该昵称已被占用,请重新输入昵称:')
                        message = 'login '+name
                        self.udpSocket.sendto(message.encode(),self.serverPort)
                except (ConnectionResetError,TypeError):
                    print('------服务器连接失败--------')
            self.thread_recv.start()
            self.thread_send.start()
            self.thread_send.join()
    
        def recvMsg(self):
            while True:
                try:
                    recvData,destIp = self.udpSocket.recvfrom(1024)
                    if recvData.decode() == 'exit' and destIp == self.serverPort:
                        print('client is closed\n')
                        self.udpSocket.close()
                        break
                    print(recvData.decode())
                except (ConnectionResetError,TypeError):
                    print('------服务器连接失败--------')
                
        def sendMsg(self):
            while True:
                    dataInfo = input()
                    self.udpSocket.sendto(dataInfo.encode(),self.serverPort)
                    if dataInfo == 'exit':
                        print('-------连接关闭-------')
                        break
    
    if if__name__=='__main__':
        	postAdd = input('请输入服务器的IP地址: ')
        	postNum = int(input('请输入服务器的端口号: '))
        	client = Client((postAdd,postNum))
       		client.start()
    
         
    

标签:第三次,self,send,server,计算机网络,msg,厦门大学,recv,addr
来源: https://blog.csdn.net/Ramezes_Dong/article/details/121468748

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有