Linux编程—网络编程

推荐socket文章

网络编程(socket套接字)

相比于依赖Linux内核的IPC——管道、消息队列、共享内存、信号、信号量来说,socket适用于多机通信。
1.相关概念:
网络字节序
字节序有Little endian小端字节序 和 Big endian大端字节序,网络字节序属于大端字节序。小端字节序是将低字节序存储在起始地址,大端字节序是将高字节序存储在起始地址。

IP地址和端口号
IP地址用来在网络连接中标识主机,相当于电话的电话号码,一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等。这些服务都是通过IP地址来实现的。主机区分网络服务不能只靠IP地址,因为IP地址于网络服务的关系是一对多的关系。实际上通过IP地址加端口号来区分不同的服务。端口号提供访问通道,服务器一般都是通过知名端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69;

TCP/HTTP/UDP协议:数据传输协议,TCP面向连接,用于对数据要求高(发送控制指令)。UDP面向报文,用于大数据量的传输。

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

网络编程步骤和API

网络编程
socket
bind
listem
accept
数据收发1
数据收发2
客户端connect
结构体查找
网络地址转换
字节序转换

服务端TCP server

	1.int socket(int domain, int type, int protocol);//创建套接字
	2.int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//绑定IP地址和端口号
	3.int listen(int sockfd, int backlog);//监听网络连接
	4.accept()//等待客户端的介入
	5.read,write//数据交互
	6.int close(int sockfd);//关闭套接字,断开网络连接

客户端TCP client

	1.socket()//创建套接字
	2.connect()//
	3.read,write//数据交互
	4.close()//关闭套接字

实现双方聊天

以下demo都是先执行服务端,后执行客户端,程序在shell执行是设定为三个参数,第一个参数为路径与程序名,第二个参数是在同一网段可ping的IP地址,第三个参数为自设的端口号
服务端:

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

#define RL 1024

int main(int argc,char **argv)
{
        if(argc != 3)
        {
                perror("参数不正确。\n");
                exit(-1);
        }
        //>>>>>>>>>>>>>>>>>>>>>>>>>>

        //定义套接字和bind配置需要的结构体
        int s_fd;
        int c_fd;
        char readbuf[RL];
	char writebuf[RL];
        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr;

        //1.socket创建套接字
        s_fd = socket(AF_INET,SOCK_STREAM,0);
        if(s_fd == -1)
        {
                printf("创建套接字失败!\n");
                perror("原因:");
                exit(-1);
        }else{
                printf("IP:%s Prot:%s\n",argv[1],argv[2]);
        }

        //2.bind绑定IP地址和端口号,配置网络协议
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(atoi(argv[2]));
        inet_aton(argv[1],&s_addr.sin_addr);

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

        //3.listen监听客户端连接请求(三次握手)
        listen(s_fd,7);

        //4.accept连接完成三次握手的客户端
        int clen=sizeof(struct sockaddr_in);
	
	while(1)
	{
       		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
       		if(c_fd == -1)
        	{
               		 printf("客户端连接失败!\n");
               		 exit(-1);
       		}else{
              		printf("客户端连接进入...\n");
                	printf("客户端IP:%s\n",inet_ntoa(c_addr.sin_addr));
              		printf("客户端连接成功。\n");
        	}

        //5.read write与客户端的数据交互
		if(fork()==0)
		{
			pid_t ip;
			ip=fork();
			if(ip==0)
			{
				while(1)
				{
               				 memset(readbuf,0,sizeof(readbuf));
              				 read(c_fd,readbuf,sizeof(readbuf));
               				 printf(">收到信息:%s\n",readbuf);
                			 if(strstr(readbuf,"quit"))break;
				}
			}else if(ip>0){
				while(1)
				{
					memset(writebuf,0,sizeof(writebuf));
					printf(">");
					gets(writebuf);
					write(c_fd,writebuf,strlen(writebuf));
				}
			}else{
				printf("连接客户端失败!\n");
			}
		}	
        }
        return 0;
}

客户端:

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

#define RL 124

int main(int argc,char **argv)
{
        if(argc != 3)
        {
                perror("参数不正确。\n");
                exit(-1);
        }
        //>>>>>>>>>>>>>>>>>>>>>>>>>>

        //定义套接字和bind配置需要的结构体
        int c_fd;
        char readbuf[RL];
        struct sockaddr_in c_addr;

        //1.socket创建套接字
        c_fd = socket(AF_INET,SOCK_STREAM,0);
        if(c_fd == -1)
        {
                printf("创建套接字失败!\n");
                perror("原因:");
                exit(-1);
        }else{
                printf("IP:%s Prot:%s\n",argv[1],argv[2]);
        }

        //2.connect连接服务端
        c_addr.sin_family = AF_INET;
        c_addr.sin_port = htons(atoi(argv[2]));
        inet_aton(argv[1],&c_addr.sin_addr);

        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in))==-1)
        {
                printf("连接服务端失败!\n");
                perror("原因:");
                exit(-1);
        }else{
                printf("连接服务端成功。\n");
        }

        //3.read write与客户端的数据交互
	if(fork()==0)
	{
		while(1)
		{
			memset(readbuf,0,sizeof(readbuf));
                	printf("input:");
                	gets(readbuf);
                	write(c_fd,readbuf,sizeof(readbuf));
		}
	}
	while(1)
	{
               	memset(readbuf,0,sizeof(readbuf));
                read(c_fd,readbuf,sizeof(readbuf));
                printf("收到信息:%s\n",readbuf);
	}
                //if(strstr(readbuf,"quit"))break;
        return 0;
}

FTP服务器

客户端:

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

#define RL 10240
#define FORBID 0
char readbuf[RL]={0};
char writebuf[64]={0};

//客户端文件上传到服务端的功能函数
int uploadFunction(int c_fd)
{   
    FILE *hafile;
    memset(readbuf,0,sizeof(readbuf));
    char *file=writebuf+strlen("upload ");
    printf("我要上传:%s||%s\n",file,readbuf);
    hafile=fopen(file,"r");
    if(hafile==NULL)
    {
        printf("上传%s失败,文件是否存在?是否有执行权限!\n",file);
        return -1;
    }else{
        write(c_fd,writebuf,strlen(writebuf));
        memset(readbuf,0,sizeof(readbuf));
        fread(readbuf,1,sizeof(readbuf),hafile);
        sleep(1);
        write(c_fd,readbuf,strlen(readbuf));
        printf("上传文件成功。\n");
        fclose(hafile);
        memset(readbuf,0,sizeof(readbuf));
    }

    return 0;
}

//从服务端下载文件的功能函数
int downloadFunction(int c_fd)
{
    FILE *dwfile;
    memset(readbuf,0,sizeof(readbuf));
    read(c_fd,readbuf,sizeof(readbuf));
    char *file=readbuf+strlen("download ");
    printf("我要下载:%s\n",file);
    dwfile=fopen(file,"w+");
    if(dwfile==NULL)
    {
        printf("下载%s失败!\n",file);
        return -1;
    }else{
        memset(readbuf,0,sizeof(readbuf));
        read(c_fd,readbuf,sizeof(readbuf));
        fwrite(readbuf,1,strlen(readbuf),dwfile);
        fclose(dwfile);
        printf("下载文件成功。\n");
    }
    return 0;
}

//执行客户端下可执行指令或程序并输出结果
int client_order(int c_fd)
{
    FILE *fp;
    fp=popen(writebuf,"r");
    if(fp==NULL)
    {
        printf("客户端执行指令失败!\n");
        return -1;
    }

    memset(readbuf,0,sizeof(readbuf));
    fread(readbuf,1,sizeof(readbuf),fp);
    printf("&&&&&&&&&&&&&&&&&&&< 客户.端 >&&&&&&&&&&&&&&&&&&&\n");
    printf("%s",readbuf);
    printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n");
    fclose(fp);
    return 0;
}

//该函数过滤不能执行的指令
int readInformation(int c_fd)
{
    int order=1;  
    if(!strcmp(writebuf,"top"))order=FORBID;
    else if(!strcmp(writebuf,"grep"))order=FORBID;
    else if(!strcmp(writebuf,"sl"))order=FORBID;
    else if(!strcmp(writebuf,"LS"))order=FORBID;
    else if(!strcmp(writebuf,"dd"))order=FORBID;
    else if(!strcmp(writebuf,"cat"))order=FORBID;
    else if(!strcmp(writebuf,"lp"))order=FORBID;
    else if(!strcmp(writebuf,"crontab"))order=FORBID;
    else if(!strcmp(writebuf,"telnet"))order=FORBID;
    else if(!strcmp(writebuf,"ftp"))order=FORBID;
    else if(!strcmp(writebuf,"nslookup"))order=FORBID;
    else if(!strcmp(writebuf,"passwd"))order=FORBID;
    else if(!strcmp(writebuf,"su"))order=FORBID;

    else if(strstr(writebuf,"ping"))order=FORBID;
    if(strstr(writebuf,"cd "))
    {
        if(chdir(writebuf+3)==-1)
        {
            perror("cd");
            return -1;
        }
        return 0;
    }
    if(order)
    {
        client_order(c_fd);
        return 0;
    }
    printf("客户端下没有或不支持该指令!\n");
    return -1;
}

int main(int argc,char **argv)
{
        //首先判断入口参数是否正确,不正确则直接退出。
        if(argc != 3)
        {
                perror("参数不正确。\n");
                exit(-1);
        }
        //>>>>>>>>>>>>>>>>>>>>>>>>>>

        printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n");
        printf("&                  FTP System                  &\n");
        printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n");
        printf("提示:上传指令upload file,下载指令download file.\n");
        printf("其余指令参考Liunx下的shell指令。\n");
        printf("(切换客户端指令->CLIENT)服务端命令发送:\n");

        //定义套接字和bind配置需要的结构体
        int c_fd;
        struct sockaddr_in c_addr;

        int i;
        //1.socket创建套接字
        c_fd = socket(AF_INET,SOCK_STREAM,0);
        if(c_fd == -1)
        {
                printf("创建套接字失败!\n");
                perror("原因:");
                exit(-1);
        }else{
                printf("服务端(server)IP:%s Prot:%s\n",argv[1],argv[2]);
        }

        //2.客户端的配置和connect连接服务端
        c_addr.sin_family = AF_INET;
        c_addr.sin_port = htons(atoi(argv[2]));
        inet_aton(argv[1],&c_addr.sin_addr);

        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in))==-1)
        {
                printf("连接服务端失败!\n");
                perror("原因:");
                exit(-1);
        }else{
                printf("连接服务端成功。\n");
        }
        
        //3.read write与客户端的数据交互        
        //char readbuf[RL]; 接受
        //char writebuf[64];发送

        if(fork()==0)
        {
            while(1)
            {    
                memset(writebuf,0,sizeof(writebuf));          
                gets(writebuf);
                if(!strcmp(writebuf,"CLIENT"))
                {
                    printf("提示:其余指令与服务端无异。\n");
                    while(1)
                    {   
                        i=1;
                        printf("进入客户端(退出指令->QUIT):");
                        memset(writebuf,0,sizeof(writebuf));
                        gets(writebuf);
                        if(strstr(writebuf,"upload "))
                        {
                            i=0;
                            uploadFunction(c_fd);
                        }
                        if(!strcmp(writebuf,"QUIT"))break;
                        if(i)readInformation(c_fd);
                    }
                    printf("退出客户端命令页,进入服务端命令页。\n");
                    printf("(切换客户端指令->CLIENT)服务端命令发送:");
                    continue;
                } 
                if(strstr(writebuf,"upload "))
                {
                    printf("该命令在客户端页使用。\n");
                    continue;
                }
                write(c_fd,writebuf,sizeof(writebuf));
                if(!strcmp(writebuf,"quit"))
                {
                    printf("退出客户端。\n");
                    exit(0);
                }          
            }
        }
        else{
            while(1)
            {
                i=1;
                memset(readbuf,0,sizeof(readbuf));
                read(c_fd,readbuf,sizeof(readbuf));
                if(!strcmp(readbuf,"quit"))exit(0);
                if(strstr(readbuf,"nofile"))
                {
                    i=0;
                    printf("没有这个文件!\n");
                }
                if(!strcmp(readbuf,"hafile"))
                {
                    i=0;
                    downloadFunction(c_fd);
                }
                if(i)puts(readbuf);
            }
        }    
        return 0;
}

服务端:

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

#define RL 10240
#define HAVEORDER1 1
#define HAVEORDER2 2
#define HAVEORDER3 3
#define CDORDER4 4

char readbuf[64]={0};
char writebuf[RL]={0};

//实现服务端文件下载到客户端的功能函数
int downloadFunction1(int c_fd)
{
    FILE *dwfile;
    write(c_fd,readbuf,strlen(readbuf));
    char *file=readbuf+strlen("download ");
    printf("下载文件:%s\n",file);
    sleep(1);
    dwfile=fopen(file,"r");
    if(dwfile==NULL)
    {
        printf("啊偶!下载失败。\n");
        return -1;
    }else{
        memset(writebuf,0,sizeof(writebuf));
        fread(writebuf,1,sizeof(writebuf),dwfile);
        write(c_fd,writebuf,strlen(writebuf));
        printf("下载成功。\n");
    }
    return 0;
}

int downloadFunction0(int c_fd)
{
    FILE *dwfile;
    char *nofile={"nofile"};
    char *hafile={"hafile"};

    char *file=readbuf+strlen("download ");
    printf("下载文件:%s\n",file);
    dwfile=fopen(file,"r");
    if(dwfile==NULL)
    {
        write(c_fd,nofile,strlen(nofile));
        printf("下载文件失败!\n");
        return 0;
    }
    write(c_fd,hafile,strlen(hafile));
    sleep(1);
    fclose(dwfile);
    return 1;
}

//实现客户端文件上传到服务端的功能函数
int uploadFunction(int c_fd)
{
    FILE *upfile;

    char *file=readbuf+strlen("upload ");
    printf("上传文件:%s\n",file);

    upfile=fopen(file,"w+");
    if(upfile==NULL)
    {
        printf("上传%s失败!\n",file);
        return -1;
    }else{
        printf("上传文件成功。\n");
        memset(writebuf,0,sizeof(writebuf));
        read(c_fd,writebuf,sizeof(writebuf));
        fwrite(writebuf,1,strlen(writebuf),upfile);
        fclose(upfile);
        memset(writebuf,0,sizeof(writebuf));
    }
    return 0;
}

//发送简单指令的执行信息
int orderFunction(int c_fd)
{
    FILE *fp;
    char *client_Input_hint={"\n(切换客户端指令->CLIENT)服务端命令发送:"};
    char *first={"收到信息:"};

    fp=popen(readbuf,"r");
    if(fp==NULL)
    {
        write(c_fd,"服务器执行指令失败!",10);
        return -1;
    }
    char *decorate0={"\n<<><><><><><><><><>< 服务.端 ><><><><><><><><><>>\n"};
    char *decorate1={"<><><><><><><><><><><><>.<><><><><><><><><><><><>"};

    memset(writebuf,0,sizeof(writebuf));
    fread(writebuf,1,sizeof(writebuf),fp);
    write(c_fd,first,strlen(first));
    write(c_fd,decorate0,strlen(decorate0));
    write(c_fd,writebuf,strlen(writebuf));
    write(c_fd,decorate1,strlen(decorate1));
    write(c_fd,client_Input_hint,strlen(client_Input_hint));
    fclose(fp);
    return 0;
}

//判断服务端中是否有客户端输入的指令
int readInformation()
{
    int order=0;
    if(!strcmp(readbuf,"ls"))order=HAVEORDER1;
    else if(!strcmp(readbuf,"pwd"))order=HAVEORDER1;
    else if(!strcmp(readbuf,"ps"))order=HAVEORDER1;
    else if(!strcmp(readbuf,"ls -l"))order=HAVEORDER1;
    else if(!strcmp(readbuf,"date"))order=HAVEORDER1;
    else if(!strcmp(readbuf,"ifconfig"))order=HAVEORDER1;
    else if(!strcmp(readbuf,"ls -al"))order=HAVEORDER1;
    else if(!strcmp(readbuf,"df"))order=HAVEORDER1;

    else if(strstr(readbuf,"cat "))order=HAVEORDER1;
    else if(strstr(readbuf,"whereis"))order=HAVEORDER1;
    else if(strstr(readbuf,"find"))order=HAVEORDER1;
    else if(strstr(readbuf,"cd"))order=CDORDER4;

    else if(strstr(readbuf,"download "))order=HAVEORDER2;
    else if(strstr(readbuf,"upload "))order=HAVEORDER3;
    return order;
}

int cd_order()
{
    if(chdir(readbuf+3)==-1)
    {
        perror("cd");
        return -1; 
    }  
    return 0;
}

//判断客户端发送过来的指令
int writeInformation(int c_fd)
{
    char *have_Not_order={"抱歉没有或不支持这个指令,请重新输入!"};
    int ordr=0;
    ordr=readInformation();

    switch(ordr)
    {
        case HAVEORDER1:
                orderFunction(c_fd);
                    break; 
        case HAVEORDER2:
                if(downloadFunction0(c_fd))
                downloadFunction1(c_fd);
                    break;
        case HAVEORDER3:
                uploadFunction(c_fd);
                    break;
        case CDORDER4:
                cd_order();
                    break;
        default:
                write(c_fd,have_Not_order,strlen(have_Not_order));
    }

    return 0;                  
}

int main(int argc,char **argv)
{
    //首先判断参数,不对直接退出。
    if(argc != 3)
    {
        perror("参数不正确。\n");
        exit(-1);
    }
        //>>>>>>>>>>>>>>>>>>>>>>>>>>

        printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
        printf("@                  FTP   system                  @\n");
        printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");

        //定义套接字和bind配置需要的结构体
        int s_fd;
        int c_fd;
        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr;

        //1.socket创建套接字
        s_fd = socket(AF_INET,SOCK_STREAM,0);
        if(s_fd == -1)
        {
                printf("创建套接字失败!\n");
                perror("原因:");
                exit(-1);
        }else{
                printf("服务器(Server) IP:%s Prot:%s\n",argv[1],argv[2]);
        }

        //2.bind绑定IP地址和端口号,配置网络协议
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(atoi(argv[2]));
        inet_aton(argv[1],&s_addr.sin_addr);

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

        //3.listen监听客户端连接请求(三次握手)
        listen(s_fd,7);

        //4.accept连接完成三次握手的客户端
        int clen=sizeof(struct sockaddr_in);
	
	    while(1)
	    {
       		  c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
       		  if(c_fd == -1)
        	  {
        	       	printf("客户端连接进入失败!\n");
               		exit(-1);
       		  }else{
              		printf("客户端连接进入...\n");
                	printf("客户端IP:%s\n",inet_ntoa(c_addr.sin_addr));
              		printf("客户端连接成功。\n");
        	  }
        //5.read write与客户端的数据交互
                                      //char readbuf[64]; 接受指令
                                      //char writebuf[RL];发送信息
		        if(fork()==0)
		        {
                    while(1)
                    {
                         memset(readbuf,0,sizeof(readbuf));
			                   read(c_fd,readbuf,sizeof(readbuf));
                         printf("收到指令:%s\n",readbuf);
                         if(!strcmp(readbuf,"quit")){
                                printf("(客户端IP:%s)退出!\n",inet_ntoa(c_addr.sin_addr));
                                write(c_fd,"quit",4);
                                exit(0);
                         }
                         writeInformation(c_fd);
                    }
		        }
        }	
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值