您的位置:首页 > 编程语言 > C语言/C++

C语言SOCKET学习

2015-12-19 23:12 411 查看
常见的两种套接字类型

SOCK_STREAM TCP 流格式套接字

SOCK_DGRAM UDP 数据包套接字

基础知识:

struct  sockaddr   // 基本不用
{
   unsigned short sa_family;   // AF_INET

         char sa_data[14];  
};
//  AF_INET是 IPv4 网络协议的套接字类型,AF_INET6 则是 IPv6 的;而 AF_UNIX 则是 Unix 系统本地通信。
struct  sockaddr_in  //  大小一样,可以用sockaddr *引用 sockaddr_in
{

   short int sin_family;   // AF_INET , 存储在本机上,不需要转变为网络字节顺序

   unsigned short int sin_port;   //端口号,NBO

   struct in_addr  sin_addr;    // IP地址,NBO

   unsigned char sin_zero[8];    //需要memset初始化,一般不使用

};

struct in_addr
{
   unsigned long s_addr;  //  存放IP地址
};


传输时要考虑字节序的问题,HBO (Host Byte Order) 和CPU有关。NBO(Network Byte Order) 是Big-endian的写法。

例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为

addr big-endian little-endian    // 以每个字节为单位

0x0000 0x12 0xcd

0x0001 0x23 0xab

0x0002 0xab 0x34

0x0003 0xcd 0x12


下图为socket流程图,挺好的。



实际创建socket
struct sockarrd_in  server_addr;  // 目的地的信息
memset(server_addr , 0 , sizeof(server_addr));  // 清空
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port );
/**
htons()--"Host to Network Short"

htonl()--"Host to Network Long"

ntohs()--"Network to Host Short"

ntohl()--"Network to Host Long"
**/
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");   // inet_addr( ); 直接返回IP地址的网络字节格式,错误时返回-1
// printf("%s",inet_ntoa(ina.sin_addr));      相反的调用,返回字符串形式的IP地址,重复调用覆盖上次结果。
 
int socket_id = socket(AF_INET, SOCK_STEAM , 0);  //socket 描述符类型为 int
/**
如果你要固定用某个端口,就用bind绑定,一般server端使用。
bind()的用法:
一旦拥有套接字,就可以把套接字和机器上的某个端口绑定起来。
bind就是这个作用。
struct sockaddr_in my_addr;
bind(socket_id,(struct sockaddr *)my_addr,sizeof(struct sockaddr));
// 其中my_addr是sockaddr_in 类型,里面的IP地址为本机地址,端口号为要绑定的端口号。
**/
建立连接
int err = connect(socket_id, ( struct sockaddr *)server_addr, sizeof(server_addr)); // connect();错误返回-1
发送数据
int send(int sock_id, char  *str, int len, int flags);   // 返回实际发送的字节数,出错返回-1

sock_id 是你想发送数据的套接字描述符(或者是调用 socket() 或者是accept() 返回的 )
str 是指向你想发送的数据的指针。len 是数据的长度,一般为strlen(str)。 把 flags 设置为 0 就可以了。
接受数据
int recv(int sock_id, char *buf, int len, unsigned int flags);   // recv() 返回实际读入缓冲的数据的字节数。或者在错误的时候返回-1
sock_id 是要读的套接字描述符。buf 是要读的信息的缓冲。len 是buf的最大长度。flags 可以设置为0。
关闭套接字
close(sock_id);//任何在另一端读写套接字的企 图都将返回错误信息。
/**
int shutdown(int sock_id, int how);
sock_id 是你想要关闭的套接字文件描述复。how 的值是下面的其中之 一:

  0 - 不允许接受

  1 - 不允许发送

  2 - 不允许发送和接受(和close() 一样)

shutdown() 成功时返回 0,失败时返回 -1
**/
server 端:
int listen(int sock_id, int backlog);   //一般先bind绑定端口,再listen。

// sock_id 是被监听的套接字文件描述符。backlog 是在进入 队列中允许的连接数目。在发生错误的时候返回-1.
/******下面是accept(); 的使用
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
main()  
{
       int sockfd, new_fd;  
       struct sockaddr_in my_addr;  
       struct sockaddr_in their_addr;  
       int sin_size;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

my_addr.sin_family = AF_INET;

     my_addr.sin_port = htons(3490);

     my_addr.sin_addr.s_addr = "127.0.0.1";  

     bzero(&(my_addr.sin_zero);  // 清空addr.sin_zero  

     bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));  //绑定端口

listen(sockfd, 10);   // 监听,队列最大10

sin_size = sizeof(struct sockaddr_in);   // sin_size 初始化为struct sockaddr_in 的大小

     new_fd = accept(sockfd, &their_addr, &sin_size);  //第一个参数为被监听的套接字,their_addr存放发送请求地的信息。返回值为新建立连接的套接字信息。
          // 第三个参数为accept后存入their_addr 的字节数。
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: