- Unix 套接字教程
- Unix Socket - 主页
- Unix 套接字 - 什么是套接字?
- Unix 套接字 - 网络地址
- Unix Socket - 网络主机名
- Unix Socket - 客户端服务器模型
- Unix Socket - 结构
- Unix Socket - 端口和服务
- Unix Socket - 网络字节顺序
- Unix Socket - IP 地址函数
- Unix Socket - 核心功能
- Unix Socket - 辅助函数
- Unix Socket - 服务器示例
- Unix Socket - 客户端示例
- Unix Socket - 总结
- Unix 套接字有用资源
- Unix 套接字 - 快速指南
- Unix Socket - 有用资源
- Unix Socket - 讨论
Unix Socket - 服务器示例
要使进程成为 TCP 服务器,您需要按照以下步骤操作 -
使用socket()系统调用创建一个套接字。
使用bind()系统调用将套接字绑定到一个地址。对于 Internet 上的服务器套接字,地址由主机上的端口号组成。
使用listen()系统调用监听连接。
使用accept()系统调用接受连接。此调用通常会阻塞,直到客户端与服务器连接为止。
使用read()和write()系统调用发送和接收数据。
现在让我们把这些步骤以源代码的形式呈现出来。将此代码放入文件server.c中并使用gcc编译器进行编译。
#include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <netinet/in.h> #include <string.h> int main( int argc, char *argv[] ) { int sockfd, newsockfd, portno, clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n; /* First call to socket() function */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("ERROR opening socket"); exit(1); } /* Initialize socket structure */ bzero((char *) &serv_addr, sizeof(serv_addr)); portno = 5001; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); /* Now bind the host address using bind() call.*/ if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("ERROR on binding"); exit(1); } /* Now start listening for the clients, here process will * go in sleep mode and will wait for the incoming connection */ listen(sockfd,5); clilen = sizeof(cli_addr); /* Accept actual connection from the client */ newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); if (newsockfd < 0) { perror("ERROR on accept"); exit(1); } /* If connection is established then start communicating */ bzero(buffer,256); n = read( newsockfd,buffer,255 ); if (n < 0) { perror("ERROR reading from socket"); exit(1); } printf("Here is the message: %s\n",buffer); /* Write a response to the client */ n = write(newsockfd,"I got your message",18); if (n < 0) { perror("ERROR writing to socket"); exit(1); } return 0; }
处理多个连接
为了允许服务器处理多个同时连接,我们在上面的代码中进行以下更改 -
将accept语句和以下代码放入无限循环中。
连接建立后,调用fork()创建新进程。
子进程将关闭sockfd并调用doprocessing函数,并将新的套接字文件描述符作为参数传递。当两个进程完成对话时(如doprocessing()返回所示),该进程将直接退出。
父进程关闭newsockfd。由于所有这些代码都处于无限循环中,因此它会返回到accept语句以等待下一次连接。
#include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <netinet/in.h> #include <string.h> void doprocessing (int sock); int main( int argc, char *argv[] ) { int sockfd, newsockfd, portno, clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n, pid; /* First call to socket() function */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("ERROR opening socket"); exit(1); } /* Initialize socket structure */ bzero((char *) &serv_addr, sizeof(serv_addr)); portno = 5001; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); /* Now bind the host address using bind() call.*/ if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("ERROR on binding"); exit(1); } /* Now start listening for the clients, here * process will go in sleep mode and will wait * for the incoming connection */ listen(sockfd,5); clilen = sizeof(cli_addr); while (1) { newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) { perror("ERROR on accept"); exit(1); } /* Create child process */ pid = fork(); if (pid < 0) { perror("ERROR on fork"); exit(1); } if (pid == 0) { /* This is the client process */ close(sockfd); doprocessing(newsockfd); exit(0); } else { close(newsockfd); } } /* end of while */ }
以下代码段显示了doprocessing函数的简单实现。
void doprocessing (int sock) { int n; char buffer[256]; bzero(buffer,256); n = read(sock,buffer,255); if (n < 0) { perror("ERROR reading from socket"); exit(1); } printf("Here is the message: %s\n",buffer); n = write(sock,"I got your message",18); if (n < 0) { perror("ERROR writing to socket"); exit(1); } }