天天看点

linux下socket编程基础示例

本文主要用于记录(因为有道云容易丢失数据),代码并不规范,所有的内容都写在main()函数里面了,主要目的是为了方便自己理清流程。

服务端的代码:

#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/time.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<signal.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "cs1.h"

void log_error(){
	printf("errno = %s\n", strerror(errno));
}


void sig_handle(int sig){
	printf("接收到了一个信号: %d\n", sig);
	switch(sig){
		case SIGPIPE:
			printf("收到SIGPIPE...\n");
			break;
	}
}


int main(){
	
	//定义变量
	int server_fd;
	int client_fd;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;//客户端
	int client_addr_len;
	int bind_res;
	int listen_res;
	int select_res;
	fd_set fd_read_set;
	fd_set temp_read_set;
	fd_set fd_write_set;
	fd_set temp_write_set;
	int select_count = 1;
	int fd_arr[1000];
	int temp_fd;
	int ioctl_res;
	int read_len;
	int write_len;
	char read_buf[1024];
	char* client_ip;
	int client_port;
	int write_res;

	//设置信号处理函数
	//对一个对端已经关闭的socket调用两次write, 
	//第二次将会生成SIGPIPE信号, 该信号默认结束进程
	struct sigaction sa;
	sa.sa_handler = sig_handle;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGPIPE, &sa, NULL);


	//初始化
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
        server_addr.sin_addr.s_addr = inet_addr(IP);	

	//创建socket
	server_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(server_fd == -1){
		printf("socket()调用失败...\n");
		log_error();
		exit(EXIT_FAILURE);
	}
	printf("server_fd = %d\n", server_fd);
	fd_arr[0] = server_fd;
	
	//bind
	bind_res = bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
	if(bind_res == -1){
		printf("bind()调用失败...\n");
		log_error();
		exit(EXIT_FAILURE);
	}

	//listen
	listen_res = listen(server_fd, 5);
	if(listen_res == -1){
		printf("listen()调用失败...\n");
		log_error();
		exit(EXIT_FAILURE);
	}

	//初始化fd_set
	FD_ZERO(&fd_read_set);
	FD_ZERO(&fd_write_set);
	FD_SET(server_fd, &fd_read_set);

	while(1){
		temp_read_set = fd_read_set;
		temp_write_set = fd_write_set;
		printf("select()调用之前----------------------------------\n");
		//select()每次调用之后都会改变传进去的集合
		//将准备好的fd留在集合里面,将没有准备好的从集合里面删除
		//这是很关键的一点
		select_res = select(FD_SETSIZE, &temp_read_set,\
			&temp_write_set, NULL, NULL);
		if(select_res == -1){
			printf("select()发生了错误\n");
			log_error();
			exit(EXIT_FAILURE);
		}
		printf("准备好了的fd个数 = %d\n", select_res);
		printf("select_count = %d\n", select_count);
		for(int i = 0; i < select_count; i++){
			temp_fd = fd_arr[i];
			printf("temp_fd = %d.......................\n", temp_fd);
			//printf("server_fd = %d\n", server_fd);
			if(temp_fd == server_fd){ //服务端准备好了
				if(FD_ISSET(temp_fd, &temp_read_set)){
					printf("服务端读准备好了...\n");
					client_addr_len = sizeof(client_addr);
					client_fd = accept(server_fd,\
							(struct sockaddr*)&client_addr,&client_addr_len);
					if(client_fd == -1){
						printf("accept()调用失败\n");
						log_error();
						continue;
					}
					if(select_count < 1000){
						fd_arr[select_count] = client_fd;
						select_count++;
						FD_SET(client_fd, &fd_read_set);
						FD_SET(client_fd, &fd_write_set);
						//break;
					}else{
						printf("fd_arr已经满了,不再接收\n");
					}
				}
			}else{ //客户端准备好了
				if(FD_ISSET(temp_fd, &temp_read_set)){
					printf("客户端读准备好了...\n");
					ioctl_res = ioctl(temp_fd, FIONREAD, &read_len);
					if(ioctl_res == -1){
						printf("ioctl()调用发生错误\n");
						log_error();
						exit(EXIT_FAILURE);
					}
					printf("read_len = %d\n", read_len);
					read_len = read_len > 1022 ? 1023 : read_len;
					if(read_len > 0){
						read(temp_fd, read_buf, read_len);
						read_buf[read_len] = '\0';
						printf("temp_fd = %d, read_buf = %s\n", temp_fd,\
								read_buf);		
					}
				}

				//写准备好了
				if(FD_ISSET(temp_fd, &temp_write_set)){
					printf("客户端写准备好了\n");
					//client_ip = inet_ntoa(client_addr.sin_addr);
					//client_port = ntohs(client_addr.sin_port);
					client_ip = read_buf;
					if(strlen(client_ip) == 0){
						printf("要发送的长度为0\n");
						continue;
					}
					write_res = write(temp_fd, client_ip, strlen(client_ip));
					printf("write_res = %d\n", write_res);
					if(write_res == -1){
						printf("write()发生错误..\n");
						log_error();
						//可能是客户端关闭了造成的
						FD_CLR(temp_fd, &fd_write_set);
						FD_CLR(temp_fd, &fd_read_set);
					}
					//write(temp_fd, &client_port, sizeof(client_port));
				}
			}
			sleep(3);

			
		}	
	
	}
			

	return 0;
}

           

客户端的代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<errno.h>
#include<string.h>
#include "cs1.h"

int main(){
	int sfd;
	struct sockaddr_in server_addr;
	char read_buf[1024];
	int addr_len;
	int co_res;
	int ioctl_res;
	int read_len;
	
	//创建socket
	sfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sfd == -1){
		printf("创建socket失败\n");
		strerror(errno);
		exit(EXIT_FAILURE);
	}
	printf("sfd = %d\n", sfd);
	//连接socket
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);//对port使用short
        server_addr.sin_addr.s_addr = inet_addr(IP);
	addr_len = sizeof(server_addr);
	printf("addr_len = %d\n", addr_len);
	co_res = connect(sfd, (struct sockaddr*)(&server_addr), addr_len);	
	if(co_res != 0){
		printf("连接失败\n");
		close(sfd);
		exit(EXIT_FAILURE);
	}
	printf("connect()调用返回,且返回值不等于0...\n");
	while(1){
		printf("循环开始----------------------------------\n");
		//向socket里面写入数据
		write(sfd, "a", 1);

		ioctl_res = ioctl(sfd, FIONREAD, &read_len);
		if(ioctl_res == -1){
			printf("ioctl()调用失败...\n");
			exit(EXIT_FAILURE);
		}
		if(read_len == 0){
			printf("read_len等于0...\n");
			//exit(EXIT_FAILURE);
		}
		printf("read_len = %d \n", read_len);
		read_len = read_len > 1022 ? 1023 : read_len;
		if(read_len > 0){
			read(sfd, read_buf, read_len);
			read_buf[read_len] = '\0';
			printf("客户端读取到的数据 = %s\n", read_buf);
		}
		printf("循环结束----------------------------------\n");

		sleep(3);
	}

	return 0;
}
           

继续阅读