Linux 网络编程——TCP

一、TCP通信步骤

TCP服务器部分:

1、调用函数socket(),创建一个socket

2、设置sockaddr_in信息,如要连接服务器的IP和端口等属性

3、调用函数bind(),绑定IP地址、端口等信息到socket上

4、调用函数listen(),设置允许的最大连接数

5、调用函数accept(),等待来自客户端的连接请求

6、调用函数send() 和 recv() 或者 read() 和 write() ,收发数据

7、调用close(),关闭网络连接

TCP客户端部分:

1、调用函数socket(),创建一个socket

2、设置sockaddr_in信息,如要连接服务器的IP和端口等属性

3、调用函数connect(),连接服务器

4、调用函数send() 和 recv() 或者 read() 和 write() ,收发数据

5、调用close(),关闭网络连接

 

从整体上看:

Linux 网络编程——TCP_第1张图片

 

服务端: 

1、创建socket

   int socket(int domain,int type,int protocol)

 

参数domain 指定使用何种的地址类型:

PF_INET / AF_INET Ipv4网络协议;

PF_UNIX / PF_LOCAL / AF_UNIX / AF_LOCAL UNIX 进程通信协议

 

type为传输类型:

 

SOCK_STREAM 提供双向连续且可信赖的数据流,即TCP。

SOCK_DGRAM 使用不连续不可信赖的数据包连接,即UDP。

protocol用来指定socket所使用的传输协议编号,通常设为0即可。

 

成功则返回新的socket处理代码,失败返回-1。

 

 

2、sockaddr_in 结构体信息填充

 

struct sockaddr_in
{
       short int sin_family;     //网络协议类型    
        unsigned short int sin_port;     //端口号
        struct in_addr sin_addr;         //目的地址结构体,其中有s_addr要做设定
        unsigned char sin_zero[8];       //无用字节为0即可,不用设置
}

 

 

0、将结构体初始化

        void bzero(void *s,int n)


      头文件为<string.h>。bzero()会将参数s所指的内存区域前n个字节,全部设为零值。相当于调用memset((void*)s,0,size_tn);

 

1、sin_family:

     协议类型与socket的domain相同。如:PF_INET

2、sin_port:

        unsigned short int htons(unsigned short int hostshort);

     htons()用来将参数指定的16位hostshort转换成网络字符顺序。返回对应的网络字符顺序。

3、sin_addr:设置的是sin_addr.s_addr

        unsigned long int inet_addr(const char *cp);

         inet_addr()用来将参数cp所指的网络地址字符串转换成网络所使用的二进制数字。网络地址字符串是以数字和点组成的字符串,例如:“127.0.0.1”。成功则返回对应的网络二进制的数字,失败返回-1。

        unsigned long int htonl(unsigned long int hostlong);

       htonl()用来将参数指定的32位hostlong 转换成网络字符顺序。返回对应的网络字符顺序。通常为INADDR_ANY。

        INADDR_ANY就是指定地址为0.0.0.0的地址,表示所有地址。 一般来说,在各个系统中均定义成为0值。

3、bind信息到socket

           int bind(int sockfd,struct sockaddr * my_addr,int addrlen);

 

    sockfd为socket函数的返回值。

    my_addr 为刚才填写的结构体,要类型转换 (SA *)&myadd。

    addrlen为结构体的大小,用sizeof函数算。

   

   成功返回0,失败返回-1。

4、listen设置连接数

             int listen(int sockfd,int backlog);
 
      listen()用来设定ssockfd的最大连接数(backlog),如果连接数目达此上限则client端将收到ECONNREFUSED的错误。Listen()并未开始接收连线,只是设置socket为listen模式,真正接收client端连线的是accept()。成功则返回0,失败返回-1。

 

5、accept等待连接请求

            int accept(int socketfd,struct sockaddr * addr,int * addrlen);
 
           accept()用来接受参数socketfd连线。当有连线进来时accept()会返回一个新的socket处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数socketfd能继续使用accept()来接受新的连线要求。

     

    连线成功时,参数addr所指的结构会被系统填入远程主机的地址数据。

 

      addrlen为scokaddr的结构长度的指针

    成功则返回新的socket处理代码,相当于文件操作符,失败返回-1。

客户端:

3、connect连接

          int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);

        用来将参数sockfd的socket连至参数serv_addr指定的网络地址。参数addrlen为sockaddr的结构长度。
      成功则返回0,失败返回-1

二、举例

//server
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<memory.h>
int main(int argc,char *argv[]){

        struct sockaddr_in sev_addr,new_addr;
        int sockfd,new_fd=0;
        char buff[1024];
        int nbytes;
        int struct_size;
        if(argc != 2){
                printf("Usage : %s <hostname>\n",argv[0]);
                return 1;
        }

        if((sockfd=socket(PF_INET,SOCK_STREAM,0))<0){
                printf("socket create error!\n");
                return 1;
        }
        bzero(&sev_addr,sizeof(struct sockaddr_in));
        sev_addr.sin_family = PF_INET;
        sev_addr.sin_port = htons(8888);
        sev_addr.sin_addr.s_addr = inet_addr(argv[1]);

        if(bind(sockfd,(struct sockaddr*)&sev_addr,sizeof(struct sockaddr_in))<0){
                printf("bind error!\n");
                return 1;
        }
        if(listen(sockfd,5)<0){
                printf("Listen set error!\n");
                return 1;
        }
        while(1){
                struct_size=sizeof(struct sockaddr_in);
                bzero(&new_addr,sizeof(struct sockaddr_in));
                if(new_fd=accept(sockfd,(struct sockaddr*)&new_addr,&struct_size)<0){
                        printf("accept error!\n");
                        return 1;
                }
                printf("The %s is conneted!\n",inet_ntoa(new_addr.sin_addr));
                memset(buff,'\0',sizeof(buff));
                if((nbytes=read(new_fd,buff,1024)) == -1){   //第一次读是从服务端输入流读入的不知是什么原因?求解释
                        printf("read error\n");
                        return 1;
                }
                printf("read over the nbytes is %d\n",nbytes);
                buff[nbytes]='\0';
                printf("Server receive the message: %s",buff);
                close(new_fd);
                printf("exit.....\n");
        }


}
 
//client
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<memory.h>
int main(int argc,char *argv[]){

        struct sockaddr_in clin_addr,new_addr;
        int sockfd,new_fd;
        char buff[1024];
        int nbytes;
        int struct_size;
        if(argc != 2){
                printf("Usage : %s <hostname>\n",argv[0]);
                return 1;
        }

        if((sockfd=socket(PF_INET,SOCK_STREAM,0))<0){
                printf("socket create error!\n");
                return 1;
        }
        bzero(&clin_addr,sizeof(struct sockaddr_in));
        clin_addr.sin_family = PF_INET;
        clin_addr.sin_port = htons(8888);
        clin_addr.sin_addr.s_addr = inet_addr(argv[1]);
        if(connect(sockfd,(struct sockaddr*)&clin_addr,sizeof(struct sockaddr_in))<0){
                printf("connect error!\n");
                return 1;  
        }
        memset(buff,'\0',1024);
        fgets(buff,1024,stdin);
        write(sockfd,buff,strlen(buff));
        close(sockfd);
        printf("client will exit!\n");
        return 0;
}



 

 

 

 

你可能感兴趣的:(Linux 网络编程——TCP)