Linux网络编程学习笔记

本文介绍了网络编程的基础知识,包括TCP/UDP协议的区别,字节序的概念,以及socket编程的主要步骤。详细讲解了socket的创建、地址绑定、监听、连接及数据收发过程。此外,还给出了FTP服务端和客户端的示例代码,展示了如何实现基本的文件传输功能。
摘要由CSDN通过智能技术生成

一:网络编程概述

        引入网络编程:进行多机通讯 

网络编程:地址+数据

  • 地址:以IP地址+端口号进行区分,IP地址可以知道主机位置,但是不知道具体运行的是哪个服务器,需要加上端口号进行区别
  • 数据即协议,也就是通过各种数据格式进行确认
  • 服务器一般都是通过知名端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69

主要协议有TCP/UDP

  • TCP面向连接,如打电话前需要拨号进行连接,而UDP无需连接,是面向报文的,即发送数据前不用建立连接
  • TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付,只能用于不需要保证数据精确度的地方
  • TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的 UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
  • 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
  • TCP首部开销20字节;UDP的首部开销小,只有8个字节
  •  TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

二:字节序

字节序是指多字节数据在计算机内存中存储或网络传输的各字节的存储数据

有小端字节序与大端字节序

小端字节序(little endian):将低序字节存放在起始位置

大端字节序(big endian):将高序字节存放在起始位置

三:socket编程

  1. 创建套接字
  2. 为套接字添加信息(IP地址和端口号)
  3. 监听网络连接
  4. 监听到有客户端介入,接受一个连接
  5. 数据交互
  6. 关闭套接字,断开连接

1.连接协议

int socket(int domain, int type, int protocol);
 		参数:
 			  domain:协议族,AF_INET
         	  type:通信类型,tcp协议为SOCK_STREAM
              protocal:具体的协议,一般为0,默认协议
              返回值: 文件描述符
2.准备地址

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	参数:
		sockfd:socket返回的文件描述符
		addr:地址结构指针,存放ip地址和端口编号
		addrlen  地址结构的长度
		返回值 0
	说明:地址结构体为:
		struct sockaddr 
		{
			sa_family_t sa_family;      //地址协议族
			char sa_data[14];           //地址  端口编号
		}
	这么写是为了适用于各个协议,却不能将32位的二进制IP地址和短整
	型数据的端口编号存储到一个字符数组里,所以使用另一个结构体来
	代替它:
		struct sockaddr_in
		{
         	sa_family_t     sin_family;    //地址协议族
        	in_port_t       sin_port       //端口编号,2byte
       	    struct in_addr  sin_addr;     //IP地址结构体
            unsigned char   sin_zero[8];   //填充,没有实际意义
       	};  
	注:该结构体在/usr/include/netinet/in.h里已被定义,
		头文件为<netinet/in.h> ;
3.监听

	int listen(int sockfd, int backlog);
     	参数  sockfd  文件描述符
              backlog 等待队列元素个数
            当客户端向服务器发起连接时,服务器的监听描述符在端口上收到了
            客户端的连 接请求后,并不是立刻建立连接,而是先将请求放在等
            待的队列中,然后从队列中按照先后顺序取出请求,建立连接。
    	返回值  0代表成功
4.连接

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
	参数:sockfd:监听用文件描述符
		  Addr:入参,是连接来的客户端的地址结构
          addrlen   地址结构的长度指针
    返回值:文件描述符 用于进行通信的描述符
5.数据收发

read/write
或send/recv
客户端用于连接

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	参数:sockfd  通信用描述符
     	  addr  目标服务器的地址结构指针
          addrlen   地址结构的长度
	返回值:成功与否 0/非0
serve.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc,char **argv)
{
	int s_fd;
	int c_fd;
	int mark = 0;
	char readBuf[128];
	char msg[128] = {0};
//	char *msg = "I get your msg\n";
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;

	memset(&s_addr,0,sizeof(struct sockaddr_in));
	memset(&c_addr,0,sizeof(struct sockaddr_in));

	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&s_addr.sin_addr);
	
	//1.socket
	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1){
		perror("socket");
		exit(0);
	}
	//2.bind
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
	//3.listen
	listen(s_fd,10);
	//4.accept
	int clen = sizeof(struct sockaddr_in);
	
	while(1){
		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
		if(c_fd == -1){
			perror("accept");
		}
		mark++;
		printf("connect ip:%s\n",inet_ntoa(c_addr.sin_addr));
		
		if(fork() == 0){
			if(fork() == 0){
				while(1){
		//6.write
					memset(msg,0,sizeof(msg));
					sprintf(msg,"welcome to %d clinet",mark);
					write(c_fd,msg,strlen(msg));
					sleep(3);
				}
			}
		
		//5.read
			while(1){
				memset(readBuf,0,sizeof(readBuf));
				int n_read = read(c_fd,readBuf,128);
				if(n_read == -1){
					perror("read");
					exit(-1);
				}else{
					printf("read meassage:%d,%s\n",n_read,readBuf);

					}
			break;
			}
		}
	}
	return 0;
}
client.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc,char **argv)
{
	int c_fd;
	int n_read;
	char readBuf[128];
//	char *msg = "msg from client\n";
	char msg[128] = {0};
	struct sockaddr_in c_addr;

	memset(&c_addr,0,sizeof(struct sockaddr_in));

	c_addr.sin_family = AF_INET;
	c_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&c_addr.sin_addr);
	
	//1.socket
	c_fd = socket(AF_INET,SOCK_STREAM,0);
	if(c_fd == -1){
		perror("socket");
		exit(0);
	}
	
	//2.connect
	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr))){
		printf("connect success\n");
	}else{
		perror("connect");
	}
	
	while(1){
		if(fork() == 0){
		//3.write
			while(1){
				memset(msg,0,sizeof(msg));
				printf("input msg:");
				gets(msg);
				write(c_fd,msg,strlen(msg));
			}
		}
		//4.read
			while(1){
				memset(readBuf,0,sizeof(readBuf));
				n_read = read(c_fd,readBuf,128);
				if(n_read == -1){
					perror("read");
					exit(-1);
				}else{
					printf("read meassage:%d,%s\n",n_read,readBuf);
				}
			}
		
	}

	return 0;
}

 

 四:FTP PROGAME

serve.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <config.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

#define LS   0
#define GET  1
#define PWD  2

#define IFGO 3

#define LCD  4
#define LLS  5
#define CD   6
#define PUT  7

#define QUIT   8
#define DOFILE 9


struct MSG
{
	int type;
	char cmd[1024];
	char dataBuf[128];
};

int get_cmd(char *cmd)
{
	if(!(strcmp("ls",cmd)))		return LS;
	if(!(strcmp("pwd",cmd)))	return PWD;
	if(!(strcmp("quit",cmd)))	return QUIT;
	if(strstr(cmd,"cd") != NULL)	return CD;
	if(strstr(cmd,"put") != NULL)	return PUT;
	if(strstr(cmd,"get") != NULL)	return GET;
	
	return 100;
}

char *getDesDir(char *cmsg)
{
	char *p;
	p = strtok(cmsg," ");
	p = strtok(NULL," ");
	return p;

}

void msg_handler(struct MSG msg,int fd)
{
	char dataBuf[1024] = {0};
	char *file = NULL;
	int ret;
	int fdfile;

	printf("cmd:%s\n",msg.cmd);
	ret = get_cmd(msg.cmd);

	switch(ret){
		case LS:
		case PWD:
			msg.type = 0;
			FILE *r = popen(msg.cmd,"r");
			fread(msg.cmd,sizeof(msg.cmd),1,r);
			write(fd,&msg,sizeof(msg));
			break;
		case CD:
			msg.type = 1;
			char *dir = getDesDir(msg.cmd);
			printf("dir:%s\n",dir);
			chdir(dir);
			break;
		case GET:
			file = getDesDir(msg.cmd);
			if(access(file,F_OK) == -1){
				strcmp(msg.cmd,"No this file\n");
				write(fd,&msg,sizeof(msg));
			}else{
				msg.type = DOFILE;
				fdfile = open(file,O_RDWR);
				read(fdfile,dataBuf,sizeof(dataBuf));
				close(fdfile);
			
				strcmp(msg.cmd,dataBuf);
				write(fd,&msg,sizeof(msg));
			}	
			break;
		case PUT:
			fdfile = open(getDesDir(msg.cmd),O_RDWR|O_CREAT,0666);
			write(fdfile,msg.dataBuf,strlen(dataBuf));
			close(fdfile);
			break;
		case QUIT:
			printf("program quit!\n");
			exit(-1);		
	}
}

int main(int argc,char **argv)
{
	int s_fd;
	int c_fd;
	int n_read;

	struct MSG msg;
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;

	if(argc != 3){
		printf("param is not correct\n");
		exit(-1);
	}	

	memset(&s_addr,0,sizeof(s_addr));
	memset(&c_addr,0,sizeof(c_addr));

	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&s_addr.sin_addr);	

	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1){
		perror("socket");
	}	


	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in)); 

	listen(s_fd,10);

	int clen = sizeof(struct sockaddr_in);

	while(1){
		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
		if(c_fd == -1){
			perror("accept");
		}
		
		printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));

		if(fork() == 0){
			while(1){					
				memset(msg.cmd,0,sizeof(msg.cmd));
				n_read = read(c_fd,&msg,sizeof(msg));
				if(n_read == 0){
					printf("client out\n");
					exit(-1);
				}else if(n_read > 0){
					msg_handler(msg,c_fd);
				}
			}
		}
			
	}

	close(s_fd);
	close(c_fd);

	return 0;	
}
client.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <config.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

#define LS   0
#define GET  1
#define PWD  2

#define IFGO 3

#define LCD  4
#define LLS  5
#define CD   6
#define PUT  7

#define QUIT   8
#define DOFILE 9


struct MSG
{
	int type;
	char cmd[1024];
	char dataBuf[128];
};

int get_cmd(char *cmd)
{
	if(!(strcmp("ls",cmd)))		return LS;
	if(!(strcmp("pwd",cmd)))	return PWD;
	if(!(strcmp("quit",cmd)))	return QUIT;
	if(strstr(cmd,"cd") != NULL)	return CD;
	if(strstr(cmd,"put") != NULL)	return PUT;
	if(strstr(cmd,"lcd") != NULL)	return LCD;
	if(strstr(cmd,"lls") != NULL)	return LLS;
	if(strstr(cmd,"get") != NULL)	return GET;
	
	return -1;
}

char *getDesDir(char *cmsg)
{
	char *p;
	p = strtok(cmsg," ");
	p = strtok(NULL," ");
	return p;

}

int cmd_handler(struct MSG msg,int fd)
{
	char buf[32];
	char *file = NULL;
	int ret;
	int fdfile;
	char *dir = NULL;
 
	ret = get_cmd(msg.cmd);

	switch(ret){
		case LS:
		case CD:
		case PWD:
			msg.type = 0;
			write(fd,&msg,sizeof(msg));
			break;
		case GET:
			msg.type = 2;
			write(fd,&msg,sizeof(msg));
			break;
		case PUT:
			strcmp(buf,msg.cmd);
			dir = getDesDir(buf);
			
			if(access(dir,F_OK) == -1){
				printf("No %s\n",dir);
			}else{
				fdfile = open(dir,O_RDWR);
				read(fdfile,msg.dataBuf,sizeof(msg.dataBuf));
				close(fdfile);
				write(fd,&msg,sizeof(msg));
				}
			break;
		case LLS:
			system("ls");
			break;
		case LCD:
			dir = get_cmd(msg.cmd);
			chdir(dir);	
			break;
		case QUIT:
			strcpy(msg.cmd,"quit");
			write(fd,&msg,sizeof(msg));
			close(fd);
			exit(-1);		
	}
	return ret;
}

void handler_serve_msg(int c_fd,struct MSG msg)
{
	int n_read;
	int newfilefd;
	struct MSG msgget;
	
	n_read = read(c_fd,&msgget,sizeof(msgget));

	if(n_read == 0){
		printf("serve out quit\n");
		exit(-1);
	}
	else if(msgget.type == DOFILE){
		char *p = getDesDir(msgget.cmd);
		newfilefd = open(p,O_RDWR|O_CREAT,0600);
		write(newfilefd,msgget.cmd,strlen(msgget.cmd));		
		putchar('>');
		fflush(stdout);
	}
	else{
		printf("------------------------------\n");
		printf("\n%s\n",msgget.cmd);
		printf("------------------------------\n");
		putchar('>');
		fflush(stdout);
	}
}

int main(int argc,char **argv)
{
	int s_fd;
	int c_fd;
	int n_read;

	struct MSG msg;
	struct sockaddr_in c_addr;

	if(argc != 3){
		printf("param is not correct\n");
		exit(-1);
	}	

	memset(&c_addr,0,sizeof(c_addr));

	c_addr.sin_family = AF_INET;
	c_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&c_addr.sin_addr);	

	c_fd = socket(AF_INET,SOCK_STREAM,0);
	if(c_fd == -1){
		perror("socket");
	}	

	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){
		perror("connect");
		exit(-1);
	}
	printf("connect ...\n");	
	int mark = 0;
	
	while(1){
		memset(msg.cmd,0,sizeof(msg.cmd));
		if(mark == 0)	printf(">");
		
		gets(msg.cmd);
			
		if(msg.cmd == 0){
			if(mark == 0){
				printf(">");
				continue;
			}
		}	

		mark = 1;

		int ret = cmd_handler(msg,c_fd);
		if(ret > IFGO){
			putchar('>');
			fflush(stdout);
			continue;
		}
		if(ret == -1){
			printf("cmd error\n");
			putchar('>');
			fflush(stdout);
			continue;
		}
		handler_serve_msg(c_fd,msg);
	}

	close(c_fd);

	return 0;	
}

 模仿完成FTP的数据交互

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值