TCP编程API实现服务器读取客户端数据

一 TCP和client的关系和区别

TCP: 面向连接 是可靠传输 (服务器)
client :客户端 有独立的ipv地址  一个或者两个(对于linux来说)
区别:客户端是主动的  服务器是被动的 
原因:服务器因为是先存在了  处于一种阻塞状态(被动等待) 客户端随时都可以连接 (主动连接)

二 创建流程

在这里插入图片描述

三 tcp 服务器

1 socket 函数

在这里插入图片描述
在这里插入图片描述

1 一般为ipv4:选 AF_INET 
2:选tcp 对应的参数
32不选 原始套接字 就填0 
套接字类似 我们串口的波特率  只是一种交流方式  
这里选择对应参数 就是 最合适的

2 bind 函数

在这里插入图片描述

TCP  为网络通信 所以选 下面 的struct sockaddr_in 类型的。
但是 bind 函数 第二个参数 是不一样的 也就是第一个结构体类型的
他在里面定义的数组就是存放 第二个结构体 的最后三个参数的 
其实 就是 先 间接 用 第二个结构体变量的方式 赋值  最后转为 第一个结构体的类型 

先写 bind 函数和 socket 函数

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


int main(int argc,char **argv)
{

  if(argc!=3){
  	
     perror("argc");
  }

  int s_fd = socket(AF_INET,SOCK_STREAM,0);
  if(s_fd==-1){
   perror("socket");   
  }
   struct sockaddr_in s_addr;
   struct sockaddr_in c_addr;
   
   memset(&s_addr,'\0',sizeof(s_addr));//网络编程用 memset 初始化 最好 
   memset(&c_addr,'\0',sizeof(c_addr)); 
   
   s_addr.sin_family = AF_INET;
   s_addr.sin_port  =htons(atoi(argv[2])) ;
   s_addr.sin_addr.s_addr =inet_addr(argv[1]);
   

  if(bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in))) {
         perror("bind");   
  }
  比如
  sin.sin_port=htons(5003);(端口号) 
  主机字节序 --》》网络字节序  
  并且为两个字节的 (双引号就是双字节)

在这里插入图片描述

  sin.sin_addr.s_addr=inet_addr("192.168.xx.xxx");
   ipv4地址---》》》网络字节序 二进制
   二进制就是可执行的  通过这个inet_addr函数 生成 二进制 文件 

在这里插入图片描述

3 listen函数

过于复杂  不要钻空子 

在这里插入图片描述

先简单 了解 在这  主要功能是 把 主动 状态 转变为  被动 状态 
参数二 :注意一些就行了 

4 accept 函数

在这里插入图片描述

产生一个新的连接  因为是阻塞等待  

socket.c (全部代码)

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


int main(int argc,char **argv)
{

  if(argc!=3){
  	
     perror("argc");
  }

  int s_fd = socket(AF_INET,SOCK_STREAM,0);
  if(s_fd==-1){
   perror("socket");   
  }
   struct sockaddr_in s_addr;
   struct sockaddr_in c_addr;
   
   memset(&s_addr,'\0',sizeof(s_addr));//网络编程用 memset 初始化 最好 
   memset(&c_addr,'\0',sizeof(c_addr)); 
   
   s_addr.sin_family      = AF_INET;
   s_addr.sin_port        = htons(atoi(argv[2])) ;
   s_addr.sin_addr.s_addr = inet_addr(argv[1]);
   

  if(bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in))) {
         perror("bind");   
  }
   printf("bind is success\n");
  
   listen(s_fd,10);
   
   printf("listen is success...........\n");

   char readbuff[1024];
   int  len = sizeof(struct sockaddr_in);
   int rts;
	  	 
	 int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&len);
         
	 if(c_fd<0)
	 {
	  exit(2);
	 }	 
	 printf("reveice is success client ip is %s\n ",inet_ntoa(c_addr.sin_addr));
         
     while(1){

        do{

	 bzero(readbuff,1024); 

	 rts =  read(c_fd,readbuff,1024-1);
	  
	}while(rts<1);
         
	 if(rts<0)
	 {
	   exit(1);
	 }

	 if(rts==0)
	 {
	   break;
	 }

	 printf("getmassage is %s\n",readbuff);	
  }
   
       close(c_fd);
       close(s_fd); 
    return 0;
}


四 client 客户端

1socket connect fgets 和write函数 配合使用

在这里插入图片描述

clinet.c (全部代码)

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


int main(int argc,char **argv)
{

  if(argc!=3){
     perror("argc");
  }

  int c_fd = socket(AF_INET,SOCK_STREAM,0);
  if(c_fd==-1){
   perror("socket");   
  }
   struct sockaddr_in c_addr;
   memset(&c_addr,'\0',sizeof(c_addr));
   c_addr.sin_family      = AF_INET;
   c_addr.sin_port        =htons(atoi(argv[2])) ;
   c_addr.sin_addr.s_addr =inet_addr(argv[1]);

   if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in))<0)
   {
      exit(1);
   }	   

   char writebuff[1024];
   
   while (1)
   {           
	   bzero(writebuff,1024);

           if(fgets(writebuff,1024-1,stdin)==NULL){
	        //fgets 有 换行符结尾  所以只能1024-1个输入上限
		  continue;
	   }

	write(c_fd,writebuff,strlen(writebuff));    
  }
   
   return 0;
   
}

3 服务器代码先下载 后到 客户端 (重要)
1 如果 读取只能一次  交换终端编译 
2 尽量 不要 while 循环 这么写 
int xx=aa(xx,xxx);int xx 放在while之前 
1 strlen 是函数  并且是 以'\0' 结尾 一般用于 发送数据 函数  计算 字符长度  
并且能保证字符能完整发完 (因为有'\0' 结束符了)
2 sizeof 只是计算 类型大小 和长度 
3 read 函数 一般 读取的字节却决于定义的数组大小
字节让他读满就行了
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值