- int socket(int domain, int type, int protocol);
注意:并不是上面的 type 和 protocol 可以随意组合的,如 SOCK_STREAM 不可以跟 IPPROTO_UDP 组合。当 protocol 为 0 时,会自动选择 type 类型对应的默认协议。
1.int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind() 函数把一个地址族中的特定地址赋给 socket。例如对应 AF_INET、AF_INET6 就是把一个 ipv4 或 ipv6 地址和端口号组合赋给 socket。
函数的三个参数分别为:
2.in listen(int sockfd, int backlog);
如果作为一个服务器,在调用 socket()、bind() 之后就会调用 listen() 来监听这个 socket,如果客户端这时调用 connect() 发出连接请求,服务器端就会接收到这个请求。
listen 函数的第一个参数即为要监听的 socket 描述字,第二个参数为相应 socket 可以排队的最大连接个数。socket() 函数创建的 socket 默认是一个主动类型的,listen 函数将 socket 变为被动类型的,等待客户的连接请求。
3.int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept 函数的第一个参数为服务器的 socket 描述字,第二个参数为指向 struct sockaddr * 的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果 accpet 成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的 TCP 连接。
注意:accept 的第一个参数为服务器的 socket 描述字,是服务器开始调用 socket() 函数生成的,称为监听 socket 描述字;而 accept 函数返回的是已连接的 socket 描述字。一个服务器通常通常仅仅只创建一个监听 socket 描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接 socket 描述字,当服务器完成了对某个客户的服务,相应的已连接 socket 描述字就被关闭。
TCP 服务器端依次调用 socket()、bind()、listen() 之后,就会监听指定的 socket 地址了。TCP 客户端依次调用 socket()、connect() 之后就想 TCP 服务器发送了一个连接请求。TCP 服务器监听到这个请求之后,就会调用 accept() 函数取接收请求,这样连接就建立好了。之后就可以开始网络 I/O 操作了,即类同于普通文件的读写 I/O 操作。
- int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。
至此服务器与客户已经建立好连接了。可以调用网络 I/O 进行读写操作了,即实现了网络中不同进程之间的通信!网络 I/O 操作有下面几组:
在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的 socket 描述字,好比操作完打开的文件要调用 fclose 关闭打开的文件。
- int close(int fd);
close 一个 TCP socket 的缺省行为时把该 socket 标记为以关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为 read 或 write 的第一个参数。
注意:close 操作只是使相应 socket 描述字的引用计数 - 1,只有当引用计数为 0 的时候,才会触发 TCP 客户端向服务器发送终止连接请求。
PS:struct sockaddr 是通用的套接字地址,而 struct sockaddr_in 则是 internet 环境下套接字的地址形式,二者长度一样,都是 16 个字节。二者是并列结构,指向 sockaddr_in 结构的指针也可以指向 sockaddr。一般情况下,需要把 sockaddr_in 结构强制转换成 sockaddr 结构再传入系统调用函数中。
代码示例:
①TCP(Transmission Control Protocol,传输控制协议)面向连接的协议:
- //server.c
- #include /* See NOTES */
- #include
- #include <string.h>
- #include
- #include in.h>
- #include
- #include
- #include
- #include
- /* socket
- * bind
- * listen
- * accept
- * send/recv
- */
- #define SERVER_PORT 8888
- #define BACKLOG 10
- int main(int argc, char **argv)
- {
- int iSocketServer;
- int iSocketClient;
- struct sockaddr_in tSocketServerAddr;
- struct sockaddr_in tSocketClientAddr;
- int iRet;
- int iAddrLen;
- int iRecvLen;
- unsigned char ucRecvBuf[1000];
- int iClientNum = -1;
- //将SIGCHLD信号的操作设为SIG_IGN,内核把僵尸子进程转交给init进程去处理
- signal(SIGCHLD,SIG_IGN);
- //TCP为两条单工通讯,第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出.
- //signal(SIGPIPE, SIG_IGN);
- //IPv4 , TCP , protocal
- iSocketServer = socket(AF_INET, SOCK_STREAM, 0); //新建一个socket句柄
- if (-1 == iSocketServer)
- {
- printf("socket error!\n");
- return -1;
- }
- tSocketServerAddr.sin_family = AF_INET; //internet
- tSocketServerAddr.sin_port = htons(SERVER_PORT); /* 将端口转换成网络字节序-host to net, short */
- tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; //本机上所有的IP
- memset(tSocketServerAddr.sin_zero, 0, 8);
- iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
- if (-1 == iRet)
- {
- printf("bind error!\n");
- return -1;
- }
- iRet = listen(iSocketServer, BACKLOG); //最多同时监测BACKLOG-10路连接
- if (-1 == iRet)
- {
- printf("listen error!\n");
- return -1;
- }
- while (1)
- {
- iAddrLen = sizeof(struct sockaddr);
- //启动监听,有客户端连接时返回0
- iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
- if (-1 != iSocketClient)
- {
- iClientNum++;
- printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
- if (!fork())
- {
- /* 子进程的源码 */
- while (1)
- {
- /* 接收客户端发来的数据并显示出来 */
- iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
- if (iRecvLen <= 0)
- {
- close(iSocketClient);
- return -1;
- }
- else
- {
- ucRecvBuf[iRecvLen] = '\0';
- printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);
- }
- }
- }
- }
- }
- close(iSocketServer);
- return 0;
- }
- //client.c
- #include /* See NOTES */
- #include
- #include <string.h>
- #include
- #include in.h>
- #include
- #include
- #include
- /* socket
- * connect
- * send/recv
- */
- #define SERVER_PORT 8888
- int main(int argc, char **argv)
- {
- int iSocketClient;
- struct sockaddr_in tSocketServerAddr;
- int iRet;
- unsigned char ucSendBuf[1000];
- int iSendLen;
- if (argc != 2)
- {
- printf("Usage:\n");
- printf("%s <server_ip>\n", argv[0]);
- return -1;
- }
- iSocketClient = socket(AF_INET, SOCK_STREAM, 0);
- tSocketServerAddr.sin_family = AF_INET;
- tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
- //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
- if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)) //将一个字符串IP地址转换为一个32位的网络序列IP地址
- {
- printf("invalid server_ip\n");
- return -1;
- }
- memset(tSocketServerAddr.sin_zero, 0, 8);
- iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
- if (-1 == iRet)
- {
- printf("connect error!\n");
- return -1;
- }
- while (1)
- {
- if (fgets(ucSendBuf, 999, stdin))
- {
- iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
- if (iSendLen <= 0)
- {
- close(iSocketClient);
- return -1;
- }
- }
- }
- return 0;
- }
②.UDP(User Data Protocol,用户数据报协议)
- //server.c
- #include /* See NOTES */
- #include
- #include <string.h>
- #include
- #include in.h>
- #include
- #include
- #include
- #include
- /* socket
- * bind
- * sendto/recvfrom
- */
- #define SERVER_PORT 8888
- int main(int argc, char **argv)
- {
- int iSocketServer;
- int iSocketClient;
- struct sockaddr_in tSocketServerAddr;
- struct sockaddr_in tSocketClientAddr;
- int iRet;
- int iAddrLen;
- int iRecvLen;
- unsigned char ucRecvBuf[1000];
- int iClientNum = -1;
- iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);
- if (-1 == iSocketServer)
- {
- printf("socket error!\n");
- return -1;
- }
- tSocketServerAddr.sin_family = AF_INET;
- tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
- tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
- memset(tSocketServerAddr.sin_zero, 0, 8);
- iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
- if (-1 == iRet)
- {
- printf("bind error!\n");
- return -1;
- }
- while (1)
- {
- iAddrLen = sizeof(struct sockaddr);
- iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
- if (iRecvLen > 0)
- {
- ucRecvBuf[iRecvLen] = '\0';
- printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
- }
- }
- close(iSocketServer);
- return 0;
- }
- //client.c
- #include /* See NOTES */
- #include
- #include <string.h>
- #include
- #include in.h>
- #include
- #include
- #include
- /* socket
- * connect
- * send/recv
- */
- #define SERVER_PORT 8888
- int main(int argc, char **argv)
- {
- int iSocketClient;
- struct sockaddr_in tSocketServerAddr;
- int iRet;
- unsigned char ucSendBuf[1000];
- int iSendLen;
- int iAddrLen;
- if (argc != 2)
- {
- printf("Usage:\n");
- printf("%s <server_ip>\n", argv[0]);
- return -1;
- }
- iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);
- tSocketServerAddr.sin_family = AF_INET;
- tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
- //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
- if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
- {
- printf("invalid server_ip\n");
- return -1;
- }
- memset(tSocketServerAddr.sin_zero, 0, 8);
- #if 0
- iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
- if (-1 == iRet)
- {
- printf("connect error!\n");
- return -1;
- }
- #endif
- while (1)
- {
- if (fgets(ucSendBuf, 999, stdin))
- {
- #if 0
- iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
- #else
- iAddrLen = sizeof(struct sockaddr);
- iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0,
- (const struct sockaddr *)&tSocketServerAddr, iAddrLen);
- #endif
- if (iSendLen <= 0)
- {
- close(iSocketClient);
- return -1;
- }
- }
- }
- return 0;
- }
来源: http://www.bubuko.com/infodetail-1961387.html