TCP服务器、客户端的简单实现

1.  IP地址(IPV4   IPV6)  
 以一个32位的整形表示: 172.166.111.110  -》点分10进程   
   地址        255.255.255.255    
表示为     FF   FF   FF  FF   ->二进程  


2.IP地址分类
A类地址:0.0.0.0    --   127.255.255.255                                网络号 +  主机号  网络号高(0-7)  主机号低(8—31)
B类地址:128.0.0.0  --   191.255.255.255                        网络号高(0-15) 主机号低(16-31)
C类地址: 192.0.0.0  --   223.255.255.255                        网络号高(0-23) 主机号低(24-31)
D类地址:224.0.0.0  --   239.255.255.255                        用来做组播网络
E类地址:240.0.0.0  --   255.255.255.255                        用来做广播网络 

说明: 网络号  -》识别是那个网络  
               主机号  -》识别是那一台PC


192.168.7.6    ---》  C类地址       网络通信时必须要地址段相同
192.168.6.6    ---》  C类地址


3.端口号    -》识别主机中的哪一个进程
IP地址:识别网络中的那一套主机,端口号就是用来识别,当前主机中的哪一个进程
端口号的取值范围:1-65535    
在使用端口号时要注意:一般使用1000以后的端口号,因为1000以前的端口号,一般被系统进程占用着

-----------------------------------------------------------------------------------------------------
传输层协议:
TCP协议     UDP协议
TCP协议可靠传输协议:一般用于文件传输,与控制命令传输。
UDP协议不可传输协议:一般用于多媒体体数据传输,例如 音频,视屏


TCP协议的搭建流程:
-----------------------------客户端-----------------------------------
1.创建socket  
头文件:
      #include <sys/types.h>          /* See NOTES */
      #include <sys/socket.h>
函数原型:
       int socket(int domain, int type, int protocol);
参数一:IP协议          AF_INET             IPv4 Internet protocols          ip(7)
                            AF_INET6            IPv6 Internet protocols          ipv6(7)
                                     AF_IPX              IPX - Novell protocols
参数二:传输协议       SOCK_STREAM    ---》TCP协议
                      SOCK_DGRAM     ---》UDP协议
参数三:socket的属性    填写为0 默认属性
返回值:成功发回 新的socket文件描述符 , 失败返回  -1

2.链接服务器  connect  (难点!!!!!!!!重点!!!)
头文件:
          #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>
函数原型:
          int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数一:socket文件描述符
参数二:服务器信息结构体
参数三:服务器信息结构体的大小
返回值:链接成功返回0  链接失败返回-1

const struct sockaddr *addr 服务器信息结构体  他的所在路径为 /usr/include/linux/in.h
struct sockaddr  与 struct sockaddr_in 在使用上是等价的。

struct sockaddr_in结构体介绍:
struct sockaddr_in {
  __kernel_sa_family_t sin_family; /* Address family协议族 IPV4 还是IPV6协议*/
  __be16 sin_port; /* Port number端口号*/
  struct in_addr sin_addr; /* Internet addressIP地址*/
}

 /* Internet address. */IP地址结构体
struct in_addr {
__be32 s_addr;
};

IP地址转换函数:
#include <sys/socket.h>
#include <netinet/in.h>  -》会与linux/in.h冲突,所以在加入点分10进制转换函数后要把原来那个头文件去掉
#include <arpa/inet.h>

in_addr_t inet_addr(const char *cp);   -》点分10进制转整形 
char *inet_ntoa(struct in_addr in);   -》整形转点分10进制类型

大小端格式:在网络通信中都使用大端格式进行通信(所以我们需要转换端口号)
大端格式:低地址存储高位字节
小段格式:低地址存储低位字节
    uint16_t htons(uint16_t hostshort); -》主机序转网络序
    uint16_t ntohs(uint16_t netshort);  -》网络序转主机序


--------------------------------服务器端----------------------------------------
1.创建socket  
头文件:
      #include <sys/types.h>          /* See NOTES */
      #include <sys/socket.h>
函数原型:
       int socket(int domain, int type, int protocol);
参数一:IP协议          AF_INET             IPv4 Internet protocols          ip(7)
                            AF_INET6            IPv6 Internet protocols          ipv6(7)
                                     AF_IPX              IPX - Novell protocols
参数二:传输协议      SOCK_STREAM    ->TCP协议
                      SOCK_DGRAM     -》UDP协议
参数三:socket的属性    填写为0 默认属性
返回值:成功发回 新的socket文件描述符 , 失败返回  -1

2.绑定socket
头文件:
          #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>
函数原型:
           int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数一:创建的socket文件描述符
参数二:服务器绑定信息
参数三:服务器信息结构体的大小
返回值:成功返回0 ,失败返回-1

3.设置为监听socket
头文件:
           #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>
函数原型:
             int listen(int sockfd, int backlog);
 参数一:创建的socket文件描述符
 参数二:最大监听数  (同时可以接受多少个客户端的链接请求)
 返回值:成功返回0  失败返回-1.


4.链接服务器  (重点!!!) 他会阻塞等待客户端链接过来
头文件:
          #include <sys/types.h>          /* See NOTES */
          #include <sys/socket.h>
函数原型:
             int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数一:监听的文件描述符
参数二:客户端的信息结构体(例如客户端的IP,端口号)
参数三:成功接受客户端的信息结构体大小
返回值:接受链接请求成功,返回一个新的文件描述符,失败返回-1


--------------------------------------------------------------------------------------------------------------------------------------
练习:tcp服务器和客户端的简单通信实现
【server.c】
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
//写操作
void *write_fun(void *arg)
{
  int fd=*(int *)arg;
   char buf[50]={0};
   //输入指令
   while(1)
   {
	 scanf("%s",buf);
	 write(fd,buf,strlen(buf));
   }
}
//读操作
void *read_fun(void *arg)
{
	 int fd=*(int *)arg;
   char buf[50]={0};
   //输入指令
   while(1)
   {

	 bzero(buf,50);
	 read(fd,buf,50);
	 printf("buf=%s\n",buf);
   }
}


int main(int argv,char **argc)
{
	if(argv<3)
	{
		perror("plese input  ./server  prot  ip");
		return 0;
	}

	//1.创建TCP socket
	 int sockfd=socket( AF_INET,SOCK_STREAM ,0);
		  if(sockfd<0)
		  {
			perror("create sock fail\n");
		  }
		  else 
		  {
			printf("create sock %d\n",sockfd);
		  }
    //设置服务器绑定信息
	struct sockaddr_in  serveraddr;
	bzero(&serveraddr,sizeof(serveraddr));
	serveraddr.sin_family  = AF_INET ;  //IPV4协议 
	serveraddr.sin_port    = htons(atoi(argc[1]));  //端口号
    serveraddr.sin_addr.s_addr = inet_addr(argc[2]);//IP地址  "0.0.0.0" ->万用地址
								// htonl(INADDR_ANY)   //INADDR_ANY  ->万用IP宏   
	//2.绑定服务器
	int ret=bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
		if(ret != 0)
		{
			perror("bind fail\n");
		}
		else
		{
			printf("bind ok\n");
		}

	//3.设置为监听socket
	 ret=listen(sockfd,5);
	 if(ret != 0)
		{
			perror("listen fail\n");
		}
		else
		{
			printf("listen ok\n");
		}
		//定义一个结构体保存客户端的信息
        struct sockaddr_in  clienaddr;
		bzero(&clienaddr,sizeof(clienaddr));
		//定义一个整形保存接收的长度
		socklen_t  len=sizeof(clienaddr);
		
	//4.接收客户端的链接请求(重点!!!)
	while(1)
	{
	int newfd=accept(sockfd,(struct sockaddr *)&clienaddr,&len);
		if(newfd>0)
		{
			printf("accept OK fd=%d\n",newfd);
			printf("clien ip=%s,port=%d\n",inet_ntoa(clienaddr.sin_addr),ntohs(clienaddr.sin_port));
			
			 //写入信息携程
			 pthread_t pid;
             pthread_create(&pid,NULL,write_fun,(void *)&newfd);
			
			//读取信息线程
			 pthread_t pid1;
             pthread_create(&pid1,NULL,read_fun,(void *)&newfd);
		}
		else 
		{
			perror("accept fail\n");
		}
	}
}


----------------------------------------------------------------------------------------------------------------------------------------------
【client.c】
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void *write_fun(void *arg)
{
  int fd=*(int *)arg;
   char buf[50]={0};
   //输入指令
   while(1)
   {
	 scanf("%s",buf);
	 write(fd,buf,strlen(buf));
   }
}
 
int main(int argv,char **argc)
{
	if(argv<3)
	{
		perror("plese input  ./clien  prot  ip");
		return 0;
	}
	

	//创建TCP socket
	 int sockfd=socket( AF_INET,SOCK_STREAM ,0);
		  if(sockfd<0)
		  {
			perror("create sock fail\n");
		  }
		  else 
		  {
			printf("create sock %d\n",sockfd);
		  }
	//设置服务器信息
	struct sockaddr_in  serveraddr;
	bzero(&serveraddr,sizeof(serveraddr));
	serveraddr.sin_family  = AF_INET ;  //IPV4协议 
	serveraddr.sin_port    = htons(atoi(argc[1]));  //端口号
        serveraddr.sin_addr.s_addr = inet_addr(argc[2]);//IP地址	 

	//进行读写操作
	 char buf[50]={0};	
    	 
	//链接服务器
	int ret=connect(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
		if(ret != 0)
		{
			perror("connect fail\n");
		}
		else
		{
			  //使用一个写入线程 
             pthread_t pid;
             pthread_create(&pid,NULL,write_fun,(void *)&sockfd);
			 
			while(1)
		   {
		     bzero(buf,sizeof(buf));
			 ret=read(sockfd,buf,sizeof(buf));	
			 if(ret>0)
			 {
			 printf("buf=%s\n",buf);
		     }
			 else
			 {
			    perror("read fail\n");
				return 0;
			 }
			}
		}
	//写一个简单的聊天客户端  可以进行读写操作
}


-----------------------------------------------------------------------------------------------------------
程序运行时必须 先运行服务器程序,再运行客户端程序,并且设置端口和服务器ip地址




























    

    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值