Linux环境下的TCP/IP通信

来源:互联网 发布:淘宝开店 旺旺名字 编辑:程序博客网 时间:2024/05/16 14:11

       套接字编程最常用的通信模式是客户机/服务器模式(C/S模式)。服务器方要先启动,并监听指定端口,等待客户端的请求,根据客户端的请求提供相应服务。下面首先给出的是基于TCP的Socket编程步骤,如图所示。



1.创建套接字

   创建套接字通过socket函数来完成,该函数会创建一个Socket描述符,后续的连接建立、数据传输等操作都通过该描述符实现,它的一般形式为:

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


参数domain用来指定要创建的套接字所使用的协议栈,通常为AF_INET,表示互联网协议族(TCP/IP协议族);

参数type用来指定套接字的类型,即数据流套接字(SOCK_STREAM)或数据报套接字(SOCK_DGRAM);

参数protocol通常设为0,表示通过指定的协议栈和套接字的类型就可以确定程序中使用的具体协议,只有在无法惟一确定协议的对应关系时,才需要指定参数protocol。


函数调用成功后,返回一个Socket描述符,它是指向内部数据结构的指针;调用过程中遇到错误时返回-1,并设置相应的错误码。

2.绑定套接字

   绑定套接字是将套接字与计算机上的一个端口号相绑定,进而在该端口监听服务请求,可以使用bind函数来完成,该函数它的一般形式为:

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


参数sockfd为要绑定的Socket描述符;

参数my_addr为一个指向含有本机IP地址和端口号等信息的sockaddr结构的指针;

参数addrlen通常设为sockaddr结构的长度。

函数调用成功后,返回值为0,否则返回-1,并设置相应的错误码。


实际使用过程中,通常使用sockaddr_in结构来代替sockaddr结构,它的定义如下所示:
struct sockaddr_in {
  short int sin_family;
  unsigned short int sin_port;
  struct in_addr sin_addr;
  unsigned char sin_zero[8];
};

其中,

sa_family为套接字的协议栈地址;

sin_port为套接字的端口号;

sin_addr为套接字的IP地址;

sin_zero通常设为0,主要功能是为了与sockaddr结构在长度上保持一致。这样,指向sockaddr_in的指针和指向sockaddr的指针可以相互转换。


in_addr结构的定义为:
struct in_addr {
  unsigned short s_addr;
};
一般情况下,可以将sin_port设为0,这样系统会随机选择一个未被占用的端口号。同样,可以将sin_addr.s_addr设为INADDR_ANY,系统会自动填入本机的IP地址。如果自行设置时,需要进行字节顺序的转换。


3.监听网络端口

   监听网络端口是将套接字设为监听模式,并在套接字指定的端口上开始监听,以便对到达的服务请求进行处理。监听网络端口可以使用listen函数来完成,它的一般形式为:

   int listen(int sockfd, int backlog);


参数sockfd为进行绑定后Socket描述符;

参数backlog用来指定请求队列中允许的最大请求数,系统的默认值一般为20。一个服务请求到达时,如果请求队列已满,则客户进程将会收到拒绝连接的出错信息。

listen函数调用成功后,返回值为0,否则返回-1,并设置相应的错误码。


4.接收连接请求

   接收连接请求是从完全建立连接的队列中接受一个连接,它可以使用accept函数来完成,它的一般形式为:

   int accept(int sockfd, void *addr, int *addrlen);


参数sockfd为被监听的Socket描述符;

参数addr通常为一个指向sockaddr_in结构的指针,结构中存放提出连接请求服务的主机IP地址和端口号等信息;

参数addrlen通常设为sockaddr结构的长度。如果程序不关心客户进程的IP地址和端口号,也可以将参数addr和addrlen设为NULL。

服务器接受连接后,accept函数会返回一个新的Socket描述符,进程可以使用这个新的描述符同客户进程传输数据。如果函数调用过程中遇到错误则返回-1,同时设置相应的错误码。


5.建立连接

   建立连接的作用是与服务器建立一个TCP,它可以使用connect函数来完成,它的一般形式为:

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


参数sockfd为Socket描述符;

参数serv_addr为指向sockaddr结构的指针,该结构中存放要连接的服务器的IP地址和端口号等信息;

参数addrlen通常设为sockaddr结构的长度。

connect函数调用成功后,返回值为0,否则返回-1,并设置相应的错误码。


6.面向连接的数据传输

   面向连接的数据传输就是在发送任何数据之前,要求建立会话连接在连接成功后再进行数据传输。面向连接的数据传输可以使用send和recv函数来完成,send函数的一般形式为:

   int send(int sockfd, const void *msg, int len, unsigned int flags);


参数sockfd为准备发送数据的Socket描述符;

参数msg为一个指针,指向所要发送的数据;

参数len为希望发送的字节数;

参数flags为控制选项,一般情况下设为0即可,当然,也可以使下面几个选项的组合:

MSG_OMB:表示可以发送附加的数据;
MSG_DONTROUTE:表示目的主机在本地网络中,不需要为IP数据包查找路由表;
MSG_DONTWAIT:表示如果套接字缓冲区没有足够空闲空间,则进程立即返回。
send函数调用成功后,返回实际发送的字节数,它可能会小于希望发送的字节数len,如果调用过程中遇到错误则返回-1,同时设置相应的错误码。


   recv函数的一般形式为:

   int recv(int sockfd, void *buf, int len, unsigned int flags);


参数sockfd为准备接收数据的Socket描述符;

参数buf为存放接收数据的缓冲区;

参数len为缓冲的字节数;

参数flags为控制选项,一般情况下设为0即可,当然,也可以使下面几个选项的组合:
MSG_OOB:表示可以接收带外的数据;
MSG_PEEK:表示进程只查看缓冲区中的数据,并不将其取走,默认情况下是读取数据后,将其从缓冲区中删除;
MSG_WAITALL:表示函数在全部数据到达后才返回,否则一直阻塞。

0 0
原创粉丝点击