套接字编程1 ------ 涉及的主要API函数 - 1

TCP进行通信的过程(三次握手):

  1. 连接的发起段(通常称为客户端),向目标计算机(通常称为服务器)发送一个请求建立连接的数据包。
  2. 服务器收到请求后,对客户端的同步信号做出响应、发送自己的同步信号给客户端。
  3. 客户端对服务器端发来的同步信号进行响应。至此,连接建立完成,就可以进行数据传输了。

TCP连接的关闭:
  1. 请求主机发送一个关闭连接的请求给另一方。
  2. 另一方收到关闭连接的请求后,发送一个接收请求的确认数据包,并关闭它的socket连接。
  3. 请求主机收到确认数据包后,发送一个确认数据包,告知另一方其发送的确认信息已收到,同时请求主机关闭它的socket连接。

套接字地址结构
      结构struct sockaddr_in定义了TCP/IP协议族的套接字地址格式,定义如下:
#include <netinet/in.h>
struct sockaddr_in{
      unsigned short            sin_family;      //地址类型
      unsigned short int       sin_port;      //端口号
      struct in_addr             sin_addr;      //IP地址
      unsigned char             sin_zero[8];      //填充字节,一般赋值为0
};

      sin_family表示地址类型,对于使用TCP/IP协议进行的网络编程,该值只能是AF_INET。
      sin_addr用来存储32位的IP地址,定义如下:
struct in_addr{
      unsigned long      s_addr;
};

      设置地址信息的示例代码:
......
struct sockaddr_in sock;
sock.sin_family=AF_INET;
sock.sin_port=htons(80);    //设置端口
sock.sin_addr.s_addr=inet_addr("202.205.3.195");    //设置IP地址
memset(sock.sin_zero,0,sizeof(sock.sin_zero));    //将数组sin_zero设置为0

创建socket套接字
      通过调用函数socket创建套接字。以下示例代码创建了一个TCP套接字:
int sock_fd;
sock_fd=socket(AF_INET,SOCK_STREAM,0);      //SOCK_STREAM代表创建TCP套接字
if(sock_fd < 0){
      perror("socket error\n");
      exit(1);
}

      创建UDP协议的套接字为:
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);

建立连接
      connect函数的原型:
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

      函数connect用来在一个指定的套接字上创建一个连接,服务器的IP地址和端口号由参数serv_addr指定。通常一个面向连接的套接字(TCP套接字)只能调用一次connect函数,用于向服务器发出连接请求。而对于无连接的套接字(UDP套接字),connect函数并不建立真正的连接,它只是告诉内核与该套接字进行通信的目的地址,只有该目的地址发来的数据才会被socket接收。所以UDP套接字可以多次调用connect函数来改变与目的地址的绑定。

      connect函数的用法示例:
......
if(connect(sock_fd,(struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in)) <0){
      perror("connect error\n");
      exit(1);
}

      注意:须将serv_addr强制转换为struct sockaddr类型。

绑定套接字
      函数bind用来将一个套接字和某个端口绑定的一起。原型:
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);

      socket函数只是创建了一个套接字,它将工作在哪个端口上,程序尚未指明。因此需要用bind函数将一个套接字和某个端口绑定在一起。
      参数my_addr指定了sockfd将绑定到的本地地址,可以将my_addr的sin_addr设置为INADDR_ANY而不是某个确定的IP地址就可以绑定到任何网络接口。对于只有一个IP地址的计算机,对应的就是它的IP地址;对于有多块网卡的计算机,INADDR_ANY表示将处理来自所有网络接口上相应端口的连接请求。
      bind函数的典型用法:
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(struct sockaddr_in));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(80);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in)) <0){
      perror("bind error\n");
      exit(1);
}

监听套接字
      调用函数listen对套接字进行监听。
#include <sys/socket.h>
int listen(int s, int backlog);

      由函数socket创建的套接字是主动套接字,可以用来主动请求连接到某个服务器(通过connect函数)。但是作为服务器端的程序,通常在某个端口上监听等待来自客户端的连接请求。在服务器端,一般是先调用函数socket创建一个主动套接字,然后调用函数bind将该套接字绑定到某个端口上,接着再调用函数listen将该套接字转化为监听套接字,等待来自客户端的连接请求。
      该函数典型用法:
#define LISTEN_NUM 12      //定义连接请求队列长度
......
if(listen(sock_fd,LISTEN_NUM) <0){
      perror("listen error\n");
      exit(1);
}

接收连接
      用accept函数来接受一个连接请求。
#include <sys/types.h>
#include <sys/socket.h>
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

  • 参数s是由socket创建、经函数bind绑定到本地某一端口上,然后通过函数listen转化而来的监听套接字。
  • 参数addr用以保存发起连接请求的主机的地址和端口。
  • 参数addrlen是addr所指向的结构体的大小。
      只能对面向连接的套接字使用accept函数,此函数执行成功返回一个新的代表客户端的套接字,出错返回-1。进程可以利用这个新的套接字描述符与客户端交换数据。参数s所指定的套接字继续等待客户端的连接请求。
      参数s所指定的套接字默认被设置为阻塞方式,accept()函数将被阻塞直到有连接请求到达为止。常见用法:

int client_fd;
int client_len;
struct sockaddr_in client_addr;
......
client_len=sizeof(struct sockaddr_in);
client_fd=accept(sock_fd, (struct sockaddr *)&client_addr, &client_len);
if(conn_fd < 0){
      perror("accept");
      exit(1);
}

TCP套接字发送数据

      send()用来在TCP套接字上发送数据。
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int s, const void *msg, size_t len, int flags);

  • 函数send只能对处于连接状态的套接字使用。
  • 参数s为已建立好连接的套接字描述符,即accept函数的返回值。
  • 参数msg指向存放待发送数据的缓冲区。
  • 参数len为待发数据的长度。
  • 参数flags为控制选项,一般设置为0。
      执行成功返回实际发送数据的字节数,出错返回-1。注意,执行成功只是说明数据写入套接字的缓冲区,并不表示数据已经成功地通过网络发送到目的地。
      send函数的常见用法:
#define BUFFERSIZE 1500
char send_buf[BUFFERSIZE];
......
if(send(conn_fd, send_buf, len, 0) < 0){
    perror("send error\n");
    exit(1);
}

接收数据

      函数recv用来在TCP套接字上接收数据。其原型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int s, void *buf, size_t len, int flags);

      recv从参数s所指定的套接字描述符(必须是面向连接的套接字)上接收数据并保存到参数buf所指定的缓冲区,参数len为缓冲区长度。参数flags为控制选项,一般设置为0。如果在指定的套接字上无数据到达时,recv()将被阻塞。
      执行成功返回接收到的数据字节数,出错则返回-1。
      该函数常见用法:
char recv_buf[BUFFERSIZE];
......
if(recv(conn_fd, recv_buf, sizeof(recv_buf), 0) < 0){
      perror("recv");
      exit(1);
}

UDP套接字发送数据

      函数sendto用来在UDP套接字上发送数据。原型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);

      函数sendto与函数send类似,但它不需要套接字处于连接状态。因为是无连接的套接字,所以在使用时需要制定数据的目的地址。
  • 参数msg指向待发送数据的缓存区
  • 参数len指定了待发数据的长度
  • 参数flags控制选项,一般设置为0
  • 参数to用于指定目的地址
  • 参数tolen指定目的地址的长度

UDP套接字接收数据

      recvfrom用来在UDP套接字上接收数据。其原型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);

      函数recvfrom与函数recv功能类似,只是recv只能用于面向连接的套接字。
  • 参数buf指向接收缓冲区
  • 参数len指定了缓冲区的大小
  • 参数flags控制选项,一般设置为0
  • 参数from中保存数据的源地址
  • 参数fromlen在调用recvfrom前为参数from的长度,调用recvfrom后将保存from的实际大小
      执行成功返回实际接收数据的字节数,出错则返回-1。

关闭套接字

      函数close用来关闭一个套接字描述符,它与关闭文件描述符是类似的。
#include <unistd.h>
int close(int fd);
  • 参数fd为一个套接字描述符,该函数关闭一个套接字。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值