C网络编程 TCP半关闭练习用到的函数

1.memset(void *s,int ch,size_t n)

函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。

memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体数组进行清零操作的一种最快方法 [1]  。

memset()函数原型是extern void *memset(void *buffer, int c, int count) buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度.

2.int atoi(const char *str)

把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。

ascii to int

3.FILE *fp

FILE *fp;

fp=fopen("test.txt",wb);

   

fopen

FILE *fopen(const char *filename, const char *mode)

  • filename -- 这是 C 字符串,包含了要打开的文件名称。
  • mode -- 这是 C 字符串,包含了文件访问模式,模式如下:
模式 描述
"r" 打开一个用于读取的文件。该文件必须存在。
"w" 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。
"a" 追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。
"r+" 打开一个用于更新的文件,可读取也可写入。该文件必须存在。
"w+" 创建一个用于读写的空文件。
"a+" 打开一个用于读取和追加的文件。

fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

  • ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
  • size -- 这是要读取的每个元素的大小,以字节为单位。
  • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

fread示例

#include <stdio.h>
#include <string.h>
 
int main()
{
   FILE *fp;
   char c[] = "This is runoob";
   char buffer[20];
 
   /* 打开文件用于读写 */
   fp = fopen("file.txt", "w+");
 
   /* 写入数据到文件 */
   fwrite(c, strlen(c) + 1, 1, fp);
 
   /* 查找文件的开头 */
   fseek(fp, 0, SEEK_SET);
 
   /* 读取并显示数据 */
   fread(buffer, strlen(c)+1, 1, fp);
   printf("%s\n", buffer);
   fclose(fp);
   
   return(0);
}

fwrite

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

参数

  • ptr -- 这是指向要被写入的元素数组的指针。
  • size -- 这是要被写入的每个元素的大小,以字节为单位。
  • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。

4.Socket

serv_sk = socket(PF_INET,SOCK_STREAM,0);

bind(serv_sk,(struct sockaddr*)&serv_adr,sizeof(serv_adr))

listen(serv_sk,5);

accept(serv_sk,(struct sockaddr *)&clnt_adr,&clnt_adr_sz);

write(clnt_sk,read_cnt);

read(clnt_sk,BUF_SIZE);

5.shutdown

 shutdown(clnt_sk,SHUT_WR);

6.sockaddr_in

    sockaddr和sockaddr_in详解

    这两个结构体用来处理网络通信的地址。

    sockaddr在头文件#include <sys/socket.h>中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了,如下:

struct sockaddr {  
     sa_family_t sin_family;//地址族
    char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息               
   };
    sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下: 

è¿éåå¾çæè¿°

sin_port和sin_addr都必须是网络字节序(NBO),一般可视化的数字都是主机字节序(HBO)。

使用时这样填写:

    //struct sockaddr_in serv_adr;

    serv_adr.sin_family=AF_INET;  
    serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);  
    serv_adr.sin_port=htons(atoi(argv[1]));  

二者长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。

sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息,是一种通用的套接字地址。 
sockaddr_in 是internet环境下套接字的地址形式。所以在网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数。
例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
 
int main(int argc,char **argv)
{
    int sockfd;
    struct sockaddr_in mysock;
 
    sockfd = socket(AF_INET,SOCK_STREAM,0);  //获得fd
 
    bzero(&mysock,sizeof(mysock));  //初始化结构体
    mysock.sin_family = AF_INET;  //设置地址家族
    mysock.sin_port = htons(800);  //设置端口
    mysock.sin_addr.s_addr = inet_addr("192.168.1.0");  //设置地址
    bind(sockfd,(struct sockaddr *)&mysock,sizeof(struct sockaddr); /* bind的时候进行转化! */
    ... ...
    return 0;
}
 

两个函数 htons() 和 inet_addr()。

htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)

inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。

inet_ntoa()作用是将一个sin_addr结构体输出成IP字符串(network to ascii)。比如:

printf("%s",inet_ntoa(mysock.sin_addr));
htonl()作用和htons()一样,不过它针对的是32位的(long),而htons()针对的是两个字节,16位的(short)。
 

与htonl()和htons()作用相反的两个函数是:ntohl()和ntohs()。 

è¿éåå¾çæè¿°

INADDR_ANY

就是inet_addr("0.0.0.0")

问:很多书上都说“将sin_addr设置为INADDR_ANY,则表示所有的IP地址,也即所有的计算机”,这样的解说让人费解。

答:

  INADDR_ANY转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP,因为有些机子不止一块网卡,多网卡的情况下,这个就表示所有网卡ip地址的意思。

  当服务器的监听地址是INADDR_ANY时,意思不是监听所有的客户端IP。而是服务器端的IP地址可以随意配置,这样使得该服务器端程序可以运行在任意计算机上,可使任意计算机作为服务器,便于程序移植。将INADDR_ANY换成127.0.0.1也可以达到同样的目的。这样,当作为服务器的计算机的IP有变动或者网卡数量有增减,服务器端程序都能够正常监听来自客户端的请求。我是这么理解的。

  比如一台电脑有3块网卡,分别连接三个网络,那么这台电脑就有3个ip地址了,如果某个应用程序需要监听某个端口,那他要监听哪个网卡地址的端口呢?如果绑定某个具体的ip地址,你只能监听你所设置的ip地址所在的网卡的端口,其它两块网卡无法监听端口,如果我需要三个网卡都监听,那就需要绑定3个ip,也就等于需要管理3个套接字进行数据交换,这样岂不是很繁琐?所以出现INADDR_ANY,你只需绑定INADDR_ANY,管理一个套接字就行,不管数据是从哪个网卡过来的,只要是绑定的端口号过来的数据,都可以接收到。

7.socklen_t

windows平台下:
文件:#include<ws2tcpip.h>

linux平台下
下面两个头文件都有定义
1)#include <sys/socket.h>
2)#include <unistd.h>
 

详细定义:typedef int socklen_t;

8. 

 //struct sockaddr_in serv_adr;

serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htnl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));

Server.c

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <arpa/inet.h>  
#include <sys/socket.h>  
  
#define BUF_SIZE    30  
  
void error_handling(char *message);  
  
int main(int argc, char *argv[]){  
    int serv_sd,clnt_sd;
    FILE *fp;  
    char buf[BUF_SIZE];  
    int read_cnt;  
    struct sockaddr_in serv_adr;  
    struct sockaddr_in clnt_adr;  
    socklen_t clnt_adr_sz;  //int
      
    if(argc != 2){  
        printf("Usage : %s <port>\n",argv[0]);  
        exit(1);  
    }  

    fp = fopen("file_ssrv.c","rb");
    serv_sd = socket(PF_INET,SOCK_STREAM,0);  
    if(serv_sd == -1){  
        error_handling("socket() error");  
    }  
  
    memset(&serv_adr,0,sizeof(serv_adr));  
    serv_adr.sin_family=AF_INET;  
    serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);  
    serv_adr.sin_port=htons(atoi(argv[1]));  
  
    if(bind(serv_sd,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1){ 
        error_handling("bind() error");  
    }  
  
    listen(serv_sd,5);
    
    clnt_adr_sz = sizeof(clnt_adr);  
    clnt_sd = accept(serv_sd,(struct sockaddr *)&clnt_adr,&clnt_adr_sz);

    while(1){  
        read_cnt = fread((void *)buf,1,BUF_SIZE,fp);
    if(read_cnt<BUF_SIZE){
        write(clnt_sd,buf,read_cnt);
        break;
        }
    write(clnt_sd,buf,BUF_SIZE);
    }  
  
    shutdown(clnt_sd,SHUT_WR);
    read(clnt_sd,buf,BUF_SIZE);
    printf("Message from client:%s \n",buf);

    fclose(fp);
    close(clnt_sd); 
    close(serv_sd);
    return 0;  
}  
 

Client.c

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <arpa/inet.h>  
#include <sys/socket.h>  
  
#define BUF_SIZE    30  
  
void error_handling(char *message);  
  
int main(int argc, char *argv[]){  
    int sd;
    FILE *fp;  
    char buf[BUF_SIZE];  
    int read_cnt;  
    struct sockaddr_in serv_adr;  
  
    if(argc != 3){  
        printf("Usage : %s <IP> <port>\n",argv[0]); //argv[0]放着程序的路径 
        exit(1);  
    }  
    
    fp = fopen("receive.dat","wb");
 
    sd = socket(PF_INET,SOCK_STREAM,0);  
    if(sd == -1){  
        error_handling("socket() error");  
    }  
  
    memset(&serv_adr,0,sizeof(serv_adr));  
    serv_adr.sin_family=AF_INET;  
    serv_adr.sin_addr.s_addr=inet_addr(argv[1]);  
    serv_adr.sin_port=htons(atoi(argv[2]));  
  
    connect(sd,(struct sockaddr *)&serv_adr,sizeof(serv_adr));
    
    while((read_cnt = read(sd,buf,BUF_SIZE)) !=0 ){
    fwrite((void *)buf,1,read_cnt,fp);
    }
 
    puts("Received file data");
    write(sd,"Thank you",10);
    fclose(fp); 
    close(sd);  
  
    return 0;  
  
}  
  
void error_handling(char *message){  
  
    fputs(message,stderr);  
    fputs("\n",stderr);  
    exit(1);  
}  
 

猜你喜欢

转载自blog.csdn.net/qq_18287147/article/details/106528624
今日推荐