zl程序教程

您现在的位置是:首页 >  云平台

当前栏目

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

客户端编程 详解 socket
2023-09-11 14:16:59 时间

写在前面

上一小节我们讲了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);


在这里插入图片描述

补充第二套收发函数: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;
}

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

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;
}

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;
}


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

运行结果如下:

在这里插入图片描述


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

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;
}

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

在这里插入图片描述

ending!