Linux----网络tcp编程

网络编程 
编程 
linux操作系统 
[用户空间]          应用层                      //程序员实现
------------------------------------------------------
[内核空间]          传输层   [网络协议栈]       //内核已经实现好的 属于网络功能
                    网络层
                    数据链路层
                    物理层 

程序发送数据   
系统调用 --- 通过系统调用来使用操作系统提供的网络功能 

函数接口 --- socket 

socket:
  1. 操作系统提供的函数接口  //通过这个接口可以使用网络功能
  2. 套接字
     在使用的思路上,套接字 被抽象成了文件 
     特殊文件 --- 专门用来进行网络通信 
     文件 描述符
     read
     write 

网络编程模型:
  1.c/s 模型 
   client ----- server
   QQ   
  2.b/s 模型 
    Brower / server  //浏览器 - 服务器 
  3.p2p 模型 
    peer 2 peer   //点 对 点 

   迅雷下载 
   云盘下载
------------------------------------------------------------------------------------------------------------

c/s 模型 
  基于 两种传输协议实现 
  tcp 协议
  传输层的协议 --- 控制传输过程 
   tcp 
        特点:
        1.面向链接  
        2.可靠传输 
        3.字节流 

 应用:
      登录网站 ---tcp 
      qq登录 
  udp 协议 
    侧重  传输效率 
     udp 
       特点:
        1.无连接 
        2.不可靠
        3.数据报 
  应用:
      视频传输 

tcp的连接:
    三次握手 
    client --------------  server
           1--连接请求-->
           2<--回应------
           3---确认----->

    client //作为主动的角色    客户端
    server //被动角色              服务器

可靠传输:
       无差错
       无丢失 --- 每个字节 都编号 
       无失序 --- 
       无重复 --- 

tcp的编程:
流程
  1.建立连接 
  2.数据通信 
  
  //通信模型 cs   --- 打电话 
  
  //客户端 
  1.socket         //买了个手机 
  2.bind (可选)    // sim 卡 
  3.connect        // 拨打电话
 
  //服务器端 
  1.socket         //买了个手机 
  2.bind           // sim 卡 
  3.listen         // 监听 --待机
  4.accept         // 接听 

int socket(int domain, int type, int protocol);
功能:程序向内核提出创建一个基于内存的套接字描述符

参数:domain  地址族,PF_INET == AF_INET ==>互联网程序
                      PF_UNIX == AF_UNIX ==>单机程序
      type    套接字类型:
                SOCK_STREAM  流式套接字 ===》TCP   
              SOCK_DGRAM   用户数据报套接字===>UDP
              SOCK_RAW     原始套接字  ===》IP
      protocol 协议 ==》0 表示自动适应应用层协议。

返回值:成功 返回申请的套接字id
        失败  -1;

int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);
   功能:该函数固定有客户端使用,表示从当前主机向目标
            主机发起链接请求。
   参数:sockfd 本地socket创建的套接子id
            addr 远程目标主机的地址信息。
         addrlen: 参数2的长度。
   返回值:成功 0
              失败 -1;

//客户端
#include<stdio.h>
#include <sys/types.h>	       /* See NOTES */
#include <sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<strings.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
	
	int fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd<0)
	{
		perror("socket fail\n");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.0.165");
	printf("fd = %d\n",fd);
	

	if(connect(fd,(struct sockaddr*)&seraddr,sizeof(seraddr))<0)
	{
		perror("connect success!\n");
		return -1;
	}
	write(fd,"hello",6);
	printf("connect success\n");
	return 0;
}

int bind(int sockfd, struct sockaddr *my_addr, 
             socklen_t addrlen);
功能:如果该函数在服务器端调用,则表示将参数1相关
      的文件描述符文件与参数2 指定的接口地址关联,
      用于从该接口接受数据。

      如果该函数在客户端调用,则表示要将数据从
      参数1所在的描述符中取出并从参数2所在的接口
      设备上发送出去。

      注意:如果是客户端,则该函数可以省略,由默认
            接口发送数据。
返回值:
    成功 0 
    失败 -1

 int listen(int sockfd, int backlog);
    功能:在参数1所在的套接字id上监听等待链接。
    参数:sockfd  套接字id
          backlog 允许链接的个数。
    返回值:成功  0
            失败  -1;

int accept(int sockfd, struct sockaddr *addr, 
                socklen_t *addrlen);
   功能:从已经监听到的队列中取出有效的客户端链接并
            接入到当前程序。
   参数:sockfd 套接字id
            addr  
               如果该值为NULL ,表示不论客户端是谁都接入。
                
               如果要获取客户端信息,则事先定义变量
               并传入变量地址,函数执行完毕将会将客户端
               信息存储到该变量中。
         addrlen: 参数2的长度,如果参数2为NULL,则该值
                     也为NULL;
                 如果参数不是NULL,&len;
                  一定要写成len = sizeof(struct sockaddr);
   返回值:成功 返回一个用于通信的新套接字id;
                从该代码之后所有通信都基于该id

           失败  -1; 

//服务器
#include<stdio.h>
#include <sys/types.h>	       /* See NOTES */
#include <sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<strings.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
	//socket
	int fd = socket(AF_INET,SOCK_STREAM,0);


	if(fd<0)
	{
		perror("socket fail\n");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.0.165");
	printf("fd = %d\n",fd);
	
//bind
	if(bind(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr))<0)
	{
		perror("connect success!\n");
		return -1;
	}
	printf("connect success\n");
//listen
	if(listen(fd,5)<0)
	{
		perror("listen fail");
		return -1;
	}
//accept
	int connfd = accept(fd,NULL,NULL);

	if(connfd < 0)
	{
		perror("accept fail");
		return -1;
	}

	printf("--------client-----connectted\n");
	read(connfd,"hello",6);

	return 0;
}

   拓展:

网络通信过程 

                    QQ_A                        QQ_B
[用户空间]           |                            |
-------------------socket-----------------------socket--------------
[内核空间]      [传输层tcp]                   [传输层tcp]                              
                     | 
                  [网络层]                     [网络层]
                     |
                [数据链路层]                 [数据链路层]
                     | 
                 [物理层]  ----------------->  [物理层]

                 
网络中找到主机 ---- ip
找到主机中进程 ---- 端口号 
  端口号 
    作用: 用来标识一个进程 
    
  组成:
       16位的数据 
  
  0~65535 
  // 
  1~1023 // 知名端口号 
         80   http
         23  
         21 
  1024~50000 //系统注册的 
  >=50000     //动态的 
  
ip+端口号 ==> 网络中进程的唯一地址 

struct sockaddr  //地址的类型 

struct sockaddr_in {
           sa_family_t    sin_family; /* address family: AF_INET */
           in_port_t      sin_port;   /* port in network byte order */
           struct in_addr sin_addr;   /* internet address */
       };

       /* Internet address. */
       struct in_addr {
           uint32_t       s_addr;     /* address in network byte order */
       };
network byte order //网络字节序 ---大端 


   //字节序转换 
 #include <arpa/inet.h>

       uint32_t htonl(uint32_t hostlong);  //主机到网络 

       uint16_t htons(uint16_t hostshort);

       uint32_t ntohl(uint32_t netlong);  //网络到主机 

       uint16_t ntohs(uint16_t netshort);

//ip地址转换        
 in_addr_t inet_addr(const char *cp);
 "192.168.0.1"

练习:点对点聊天(进程或线程;一个进程读,一个进程写;一个线程读,一个线程写)

#include <stdio.h>
#include <sys/types.h>	       /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

void handler(int signo)
{
	wait(NULL);
}

//./client ip port
int main(int argc, const char *argv[])
{
	if (argc != 3)
	{
		printf("%s <ip> <port>\n",argv[0]);
		return -1;
	}

	int fd = socket(AF_INET,SOCK_STREAM,0);
	if (fd < 0)
	{
		printf("socket fail");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_addr.s_addr = inet_addr(argv[1]); 
	seraddr.sin_port = htons(atoi(argv[2]));

	if (connect(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("conncet fail");
		return -1;
	}

	pid_t pid = fork();

	if (pid < 0)
	{
		perror("fork fail");
		return -1;
	}
	char buf[1024];
	if (pid > 0)
	{
		signal(SIGCHLD,handler);

		while (1)
		{
			printf(">");
			fgets(buf,sizeof(buf),stdin);
			write(fd,buf,strlen(buf)+1);
			if (strncmp(buf,"quit",4) == 0)
			{
				kill(pid,SIGUSR1);
				wait(NULL);
				exit(0);
			}
		}

	}else if (pid == 0)
	{
		while (1)
		{
			read(fd,buf,sizeof(buf));
			printf("ser: %s",buf);
			if (strncmp(buf,"quit",4) == 0)
			{
				kill(getppid(),SIGUSR1);
				exit(0);
			}
		}

	}

	return 0;
}
#include <stdio.h>
#include <sys/types.h>	       /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

void handler(int signo)
{
	printf("father exit....\n");
	exit(0);
}

//./client ip port
int main(int argc, const char *argv[])
{
	if (argc != 3)
	{
		printf("%s <ip> <port>\n",argv[0]);
		return -1;
	}

	int fd = socket(AF_INET,SOCK_STREAM,0);
	if (fd < 0)
	{
		printf("socket fail");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_addr.s_addr = inet_addr(argv[1]); 
	seraddr.sin_port = htons(atoi(argv[2]));

	if (bind(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("bind fail");
		return -1;
	}


	if (listen(fd,5) < 0)
	{
		perror("listen fail");
		return -1;
	}

	int connfd = 0;
#if 0
	if ((connfd = accept(fd,NULL,NULL)) < 0)
	{
		perror("accept fail");
		return -1;
	}
#endif
	//while (1)
	{
		struct sockaddr_in cliaddr;
		bzero(&cliaddr,sizeof(cliaddr));
		socklen_t len = sizeof(cliaddr);
		if ((connfd = accept(fd,(struct sockaddr*)&cliaddr,&len)) < 0)
		{
			perror("accept fail");
			return -1;
		}

		printf("-------client info------\n");
		printf("ip  : %s\n",inet_ntoa(cliaddr.sin_addr));
		printf("port: %d\n",ntohs(cliaddr.sin_port));
		printf("------------------------\n");
#if 1
		pid_t pid = fork();

		if (pid < 0)
		{
			perror("fork fail");
			return -1;
		}
		char buf[1024];
		if (pid > 0)
		{
			signal(SIGUSR1,handler);
			while (1)
			{
				printf(">");
				fgets(buf,sizeof(buf),stdin);
				write(connfd,buf,strlen(buf)+1);

				if (strncmp(buf,"quit",4) == 0)
				{
					kill(pid,SIGUSR1);
					wait(NULL);
					exit(0);
				}
			}

		}else if (pid == 0)
		{
			while (1)
			{
				read(connfd,buf,sizeof(buf));

				printf("cli: %s",buf);
				if (strncmp(buf,"quit",4) == 0)
				{
					kill(getppid(),SIGUSR1);
					exit(0);
				}
			}

		}
#endif 
	}
	return 0;
}

线程

#include <stdio.h>
#include <sys/types.h>	       /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#include <errno.h>
#include <pthread.h>


void *do_write(void *arg)
{
	int fd = *(int *)arg;
	char buf[1024];
	while (1)
	{
		printf(">");
		fgets(buf,sizeof(buf),stdin);
		write(fd,buf,strlen(buf)+1);
		if (strncmp(buf,"quit",4) == 0)
		{
			exit(0);
		}
	}
}

void *do_read(void *arg)
{
	int fd = *(int *)arg;
	char buf[1024] = {0};
	while (1)
	{
		read(fd,buf,sizeof(buf));
		printf("ser: %s",buf);
		if (strncmp(buf,"quit",4) == 0)
		{
			exit(0);
		}
	}

}


//./client ip port
int main(int argc, const char *argv[])
{
	if (argc != 3)
	{
		printf("%s <ip> <port>\n",argv[0]);
		return -1;
	}

	int fd = socket(AF_INET,SOCK_STREAM,0);
	if (fd < 0)
	{
		printf("socket fail");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_addr.s_addr = inet_addr(argv[1]); 
	seraddr.sin_port = htons(atoi(argv[2]));

	if (connect(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("conncet fail");
		return -1;
	}
	pthread_t tid[2];
	int ret = 0;
	if ((ret = pthread_create(&tid[0],NULL,do_read,&fd)) != 0)
	{
		errno = ret;
		perror("pthread_create fail");
		exit(0);
	}

	if ((ret = pthread_create(&tid[1],NULL,do_write,&fd)) != 0)
	{
		errno = ret;
		perror("pthread_create fail");
		exit(0);
	}


	printf("-----main----\n");
	pthread_join(tid[0],NULL);
	pthread_join(tid[1],NULL);
	return 0;
}
#include <stdio.h>
#include <sys/types.h>	       /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#include <errno.h>
#include <pthread.h>


void *do_write(void *arg)
{
	int fd = *(int *)arg;
	char buf[1024];
	while (1)
	{
		printf(">");
		fgets(buf,sizeof(buf),stdin);
		write(fd,buf,strlen(buf)+1);
		if (strncmp(buf,"quit",4) == 0)
		{
			exit(0);
		}
	}
}

void *do_read(void *arg)
{
	int fd = *(int *)arg;
	char buf[1024] = {0};
	while (1)
	{
		int ret = read(fd,buf,sizeof(buf));
		printf("ret = %d cli: %s",ret,buf);
		if (strncmp(buf,"quit",4) == 0)
		{
			exit(0);
		}
	}

}


//./client ip port
int main(int argc, const char *argv[])
{
	if (argc != 3)
	{
		printf("%s <ip> <port>\n",argv[0]);
		return -1;
	}

	int fd = socket(AF_INET,SOCK_STREAM,0);
	if (fd < 0)
	{
		printf("socket fail");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_addr.s_addr = inet_addr(argv[1]); 
	seraddr.sin_port = htons(atoi(argv[2]));

	if (bind(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("bind fail");
		return -1;
	}


	if (listen(fd,5) < 0)
	{
		perror("listen fail");
		return -1;
	}

	int connfd = 0;
#if 0
	if ((connfd = accept(fd,NULL,NULL)) < 0)
	{
		perror("accept fail");
		return -1;
	}
#endif
	//while (1)
	{
		struct sockaddr_in cliaddr;
		bzero(&cliaddr,sizeof(cliaddr));
		socklen_t len = sizeof(cliaddr);
		if ((connfd = accept(fd,(struct sockaddr*)&cliaddr,&len)) < 0)
		{
			perror("accept fail");
			return -1;
		}

		printf("-------client info------\n");
		printf("ip  : %s\n",inet_ntoa(cliaddr.sin_addr));
		printf("port: %d\n",ntohs(cliaddr.sin_port));
		printf("------------------------\n");
#if 1
		pthread_t tid[2];
		int ret = 0;
		if ((ret = pthread_create(&tid[0],NULL,do_read,&connfd)) != 0)
		{
			errno = ret;
			perror("pthread_create fail");
			exit(0);
		}

		if ((ret = pthread_create(&tid[1],NULL,do_write,&connfd)) != 0)
		{
			errno = ret;
			perror("pthread_create fail");
			exit(0);
		}


		pthread_join(tid[0],NULL);
		pthread_join(tid[1],NULL);
#endif 
	}
	return 0;
}

练习:tcp传文件

#include <stdio.h>
#include <sys/types.h>	       /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>


typedef struct 
{
	int size;
	char data[256];
}msg_t;



//./client port ip filename 
int main(int argc, const char *argv[])
{
	if (argc != 4)
	{
		printf("Usage: %s <port> <ip> <filename>\n",argv[0]);
		return -1;
	}

	int fd = socket(AF_INET,SOCK_STREAM,0);

	if (fd < 0)
	{
		perror("socket fail\n");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(atoi(argv[1]));
	seraddr.sin_addr.s_addr = inet_addr(argv[2]);
	printf("fd = %d\n",fd);

	if (connect(fd,(struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("connect fail");
		return -1;
	}

	//名字 
	//send(fd,argv[3],strlen(argv[3])+1,0);
	send(fd,argv[3],strlen(argv[3]),0);
	sleep(1);
	//创建文件 
	int fd_s = open(argv[3],O_RDONLY);
	if (fd_s < 0)
	{
		perror("open fail");
		return -1;
	}
	char buf[1024];
	while (1)
	{
		int ret = read(fd_s,buf,sizeof(buf));
		if (ret == 0)
			break;
		send(fd,buf,ret,0);
	}

	sleep(1000);
	close(fd_s);
	close(fd);

	return 0;
}
#include <stdio.h>
#include <sys/types.h>	       /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

typedef struct 
{
	int size;
	char data[256];
}msg_t;

int main(int argc, const char *argv[])
{
	if (argc != 3)
	{
		printf("Usage: %s <port> <ip>\n",argv[0]);
		return -1;
	}
	
	//1.socket 创建通信一端 
	int fd = socket(AF_INET,SOCK_STREAM,0);

	if (fd < 0)
	{
		perror("socket fail\n");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(atoi(argv[1]));
	seraddr.sin_addr.s_addr = inet_addr(argv[2]);
	printf("fd = %d\n",fd);
    //2.bind -- 绑定服务器端的地址信息 
	if (bind(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("connect fail");
		return -1;
	}

	printf("connect success!\n");

	//3.listen -- 设置监听 
	if (listen(fd,5) < 0)
	{
		perror("listen fail");
		return -1;
	}

	//4.accept
	int connfd = accept(fd,NULL,NULL);

	if (connfd < 0)
	{
		perror("accept fail");
		return -1;
	}

	printf("----client --- connectted\n");

	char buf[1024];
	msg_t msg;
	int ret = recv(connfd,&msg,sizeof(msg),0);
	
	printf("ret = %d  %s\n",ret,msg.data);

	int fd_d = open(msg.data,O_WRONLY|O_CREAT|O_TRUNC,0666);
	if (fd_d < 0)
	{
		perror("open fail");
		return -1;
	}

	while (1)
	{
		ret = recv(connfd,&msg,sizeof(msg),0);
		printf("ret = %d  %s\n",msg.size,msg.data);

		if (msg.size == 0)
			break;
		write(fd_d,msg.data,msg.size);

	}


	close(fd);
	close(connfd);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值