• socket编程详解(二)——客户端


    写在前面

    上一小节我们讲了socket编程服务器端,也简单说了各个函数的使用说明,下面我们看看客户端是怎样完成的,以及互相聊天的实现。。。

    传送:socket编程详解(一)——服务器端

    首先我们再贴贴上一小节的图:
    在这里插入图片描述

    客户端编程的文字步骤:

    1:加载套接字库,创建套接字(WSAStartup()/socket());

    2:向服务器发出连接请求(connect());

    3:和服务器端进行通信(send()/recv());

    4:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。


    client函数api

    connect ()函数

     #include <sys/types.h>          /* See NOTES */
     #include <sys/socket.h>
    
    int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    补充第二套收发函数:send和recv函数

    send()函数和recv()函数

    在这里插入图片描述

    客户端比较简单连接上收发消息就可以了。。。。

    demo1示例

    client.c	
    
    #include <stdio.h>
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <string.h>
    int main(){
    	
    	int c_fd;
    	struct sockaddr_in c_addr;
    	char readBuf[128];
    	char *msg = "msg from client";
    
    	//void *memset(void *s, int c, size_t n);
    	memset(&c_addr,0,sizeof(struct sockaddr_in));
    
    	//1.scoket
    	//int socket(int domain, int type, int protocol);
    	c_fd = socket(AF_INET,SOCK_STREAM,0);
    	if(c_fd == -1){
    		perror("socket");
    		exit(-1);
    	}
    
    	c_addr.sin_family = AF_INET;
    	c_addr.sin_port = htons(8089);
    	inet_aton("192.168.2.40",&c_addr.sin_addr);
    
    	//2.connect	
    	//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
    		perror("connect");
    		exit(-1);
    	}
    	
    	//3.write
    	//ssize_t write(int fd, const void *buf, size_t count);
    	write(c_fd,msg,128);
    	
    	//4.read
    	//ssize_t read(int fd, void *buf, size_t count);
    	int n_read = read(c_fd,readBuf,128);
    	if(n_read == -1){
    		perror("read");
    	}else{
    		printf("msg:%d,%s\n",n_read,readBuf);
    	}
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    目前基本的框架已经完成了,不足的是只能发送一次消息,不能够持续性的聊天,我们再改进下。。。

    demo2示例

    tserver.c服务器端
    
    int main(int argc,char **argv){
    
    	int s_fd;
    	int c_fd;
    	struct sockaddr_in s_addr;
    	struct sockaddr_in c_addr;
    	char readBuf[128];
    	//char *msg = "msg from server";
    	char msg[128] = {0};
    
    	//void *memset(void *s, int c, size_t n);
    	memset(&s_addr,0,sizeof(struct sockaddr_in));
    	memset(&c_addr,0,sizeof(struct sockaddr_in));
    //加上参数判断
    	if(argc != 3){
    		printf("Parameter incomplete!\n");
    		exit(-1);
    	}
    
    	//1.scoket
    	//int socket(int domain, int type, int protocol);
    	s_fd = socket(AF_INET,SOCK_STREAM,0);
    	if(s_fd == -1){
    		perror("socket");
    		exit(-1);
    	}
    
    	s_addr.sin_family = AF_INET;
    	s_addr.sin_port = htons(atoi(argv[2]));
    	inet_aton(argv[1],&s_addr.sin_addr);
    
    	//2.bind	
    	//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
    
    	//3.listen
    	//int listen(int sockfd, int backlog);
    	listen(s_fd,10);
    
    	//4.accept
    	//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    	int len = sizeof(struct sockaddr_in);
    	while(1){//监听后不断的接收连接
    		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&len);
    		if(c_fd == -1){
    			perror("accept");
    			exit(-1);	
    		}
    		printf("connect:%s\n",inet_ntoa(c_addr.sin_addr));
    		if(fork() == 0){
    		
    //创建子进程,父进程等待连接消息,子进程来完成读写操作,写和读不断循环,随时收发,同样的客户端也要循环匹配
    			if(fork() == 0){
    				while(1){
    					//6.write
    					//ssize_t write(int fd, const void *buf, size_t count);
    					memset(msg,0,sizeof(msg));
    					printf("input: ");
    					gets(msg);
    					write(c_fd,msg,strlen(msg));
    				}
    			}
    			while(1){
    				//5.read
    				//ssize_t read(int fd, void *buf, size_t count);
    				memset(readBuf,0,sizeof(readBuf));
    				int n_read = read(c_fd,readBuf,128);
    				if(n_read == -1){
    					perror("read");
    				}else{
    					printf("msg from client:%d,%s\n",n_read,readBuf);
    				}
    			}
    		}
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    tclient.c客户端
    
    int main(int argc,char **argv){
    
    	int c_fd;
    	struct sockaddr_in c_addr;
    	char readBuf[128];
    	//char *msg = "msg from client";
    	char msg[128] = {0};
    
    	//void *memset(void *s, int c, size_t n);
    	memset(&c_addr,0,sizeof(struct sockaddr_in));
    //加上参数判断
    	if(argc != 3){
    		printf("Parameter incomplete!\n");
    		exit(-1);
    	}
    
    	//1.scoket
    	//int socket(int domain, int type, int protocol);
    	c_fd = socket(AF_INET,SOCK_STREAM,0);
    	if(c_fd == -1){
    		perror("socket");
    		exit(-1);
    	}
    
    	c_addr.sin_family = AF_INET;
    	c_addr.sin_port = htons(atoi(argv[2]));
    	inet_aton(argv[1],&c_addr.sin_addr);
    
    	//2.connect	
    	//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
    		perror("connect");
    		exit(-1);
    	}
    	while(1){
    		//3.write
    		//ssize_t write(int fd, const void *buf, size_t count);
    		if(fork() == 0){
    			while(1){
    				memset(msg,0,sizeof(msg));
    				printf("input: ");
    				gets(msg);	
    				write(c_fd,msg,strlen(msg));
    			}
    		}
    		while(1){
    			//4.read
    			//ssize_t read(int fd, void *buf, size_t count);
    			memset(readBuf,0,sizeof(readBuf));
    			int n_read = read(c_fd,readBuf,128);
    			if(n_read == -1){
    				perror("read");
    			}else{
    				printf("msg from server:\n%s\n",readBuf);
    			}
    		}
    	}
    	return 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    关于上面的父子进程的创建:
    在这里插入图片描述

    运行结果如下:

    在这里插入图片描述


    上面的只是针对单个客户端,那么实现多个客户端的消息发送呢???
    仅限客户端消息发送哈。。。。

    demo3示例

    dserver.c服务器端
    
    #include <stdio.h>
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <string.h>
    int main(int argc,char **argv){
    
    	int s_fd;
    	int c_fd;
    	struct sockaddr_in s_addr;
    	struct sockaddr_in c_addr;
    	char readBuf[128];
    	//char *msg = "msg from server";
    	char msg[128] = {0};
    	int mark = 0;
    	//void *memset(void *s, int c, size_t n);
    	memset(&s_addr,0,sizeof(struct sockaddr_in));
    	memset(&c_addr,0,sizeof(struct sockaddr_in));
    
    	if(argc != 3){
    		printf("Parameter incomplete!\n");
    		exit(-1);
    	}
    
    	//1.scoket
    	//int socket(int domain, int type, int protocol);
    	s_fd = socket(AF_INET,SOCK_STREAM,0);
    	if(s_fd == -1){
    		perror("socket");
    		exit(-1);
    	}
    
    	s_addr.sin_family = AF_INET;
    	s_addr.sin_port = htons(atoi(argv[2]));
    	inet_aton(argv[1],&s_addr.sin_addr);
    
    	//2.bind	
    	//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
    
    	//3.listen
    	//int listen(int sockfd, int backlog);
    	listen(s_fd,10);
    
    	//4.accept
    	//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    	int len = sizeof(struct sockaddr_in);
    	while(1){
    		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&len);
    		if(c_fd == -1){
    			perror("accept");
    			exit(-1);	
    		}
    		mark++;
    		printf("connect:%s\n",inet_ntoa(c_addr.sin_addr));
    		if(fork() == 0){
    			if(fork() == 0){
    				while(1){
    					//6.write
    					//ssize_t write(int fd, const void *buf, size_t count);
    					sprintf(msg,"welcome No.%d client",mark);
    					write(c_fd,msg,strlen(msg));
    					sleep(10);
    				}
    			}
    			while(1){
    				//5.read
    				//ssize_t read(int fd, void *buf, size_t count);
    				memset(readBuf,0,sizeof(readBuf));
    				int n_read = read(c_fd,readBuf,128);
    				if(n_read == -1){
    					perror("read");
    				}else{
    					printf("msg from client:\n%s\n",readBuf);
    				}
    			}
    		}
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    客户端不用改变,只需要在服务器端打印客户端号即可
    效果比较鸡肋,记录下来看看。。。。

    在这里插入图片描述

    ending!

  • 相关阅读:
    01-MySQL简介和安装
    centos8.2 OS日志重定向到串口设备ttyS0,通过bmc查看调试
    SQL-basics
    【洛谷题解/NOI2001】P2704/NOI2001炮兵阵地
    SWT Table列自适应大小
    wx.canvasToTempFilePath生成图片保存到相册
    linux内核分析:网络协议栈
    网页采集器哪个好-免费网页采集器排行榜
    十五、MySQL(DCL)如何实现用户权限控制?
    GeoJson格式标准规范
  • 原文地址:https://blog.csdn.net/qq_44333320/article/details/125451293