目录
其中read、write、close在IO中已经介绍过,只需了解socket、bind、listen、accept等

- #include
- #include
- int socket(int domain, int type, int protocol);
-
-
参数:
domain:指定套接字的协议域(protocol family),可以是 AF_INET(IPv4)或 AF_INET6(IPv6)等。type:指定套接字的类型,可以是 SOCK_STREAM(流套接字,用于可靠的、面向连接的通信)或 SOCK_DGRAM(数据报套接字,用于无连接的通信)等。protocol:指定使用的协议,可以是 IPPROTO_TCP(TCP)或 IPPROTO_UDP(UDP)等。所以无需要指定协议,设为0即可返回值:
-1,并设置 errno 来表示具体的错误原因。示例:
- #include
- #include
-
- int main() {
- int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //最后一个参数也可以是0
- if (sockfd == -1) {
- // 处理创建套接字失败的情况
- return -1;
- }
- // 套接字创建成功,可以进行后续操作
-
- return 0;
- }
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数解释:
sockfd:要进行绑定的套接字描述符。addr:指向sockaddr结构体的指针,其中包含了要绑定的地址信息。addrlen:addr指向的结构体的大小。返回值:
errno全局变量获取具体错误信息。
ipv4结构体
- struct sockaddr_in {
- sa_family_t sin_family; /* 地址族: AF_INET */
- in_port_t sin_port; /* 网络字节序的端口号 */
- struct in_addr sin_addr; /*IP地址结构体 */
- };
-
- /* IP地址结构体 */
- struct in_addr {
- uint32_t s_addr; /* 网络字节序的IP地址 */
- };
-
- /*通用地址族结构体*/
- struct sockaddr {
- sa_family_t sa_family;
- char sa_data[14];
- }
注意事项:
bind()函数之前,需要先创建一个套接字,并确保该套接字是未绑定的。bind()函数通常在服务器端使用,用于将服务器的套接字与指定的本地地址绑定,从而监听并接收该地址发来的连接请求。bind()函数时,要根据实际情况提供正确的地址信息,如IP地址和端口号等。sockaddr_in结构体中;而在IPv6中,地址信息存储在sockaddr_in6结构体中。示例:强制转换
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
-
- int main() {
- int sockfd;
- struct sockaddr_in server_addr;
-
- // 创建套接字
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
-
- // 设置服务器地址信息
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(8080);
- server_addr.sin_addr.s_addr = INADDR_ANY;
-
- // 绑定套接字和地址
- if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
- perror("bind");
- return 1;
- }
-
- // 其他操作...
-
- return 0;
- }
- /*监听套接字*/
- int listen(int sockfd, int backlog);
-
-
参数:
sockfd:要监听的套接字描述符。backlog:定义允许排队等待的连接请求的最大数量。返回值:
listen() 函数时,返回 0 表示成功。listen() 函数失败时,返回 -1 并设置 errno 来表示具体的错误原因。函数功能: listen() 函数被用于 TCP 服务器端,用于将指定的套接字标记为被动套接字(passive socket),开始监听传入的连接请求。在调用 listen() 之前,服务器需要使用 socket() 函数创建一个套接字,并使用 bind() 函数将套接字与特定的地址和端口绑定。
一旦套接字被标记为监听状态,它就可以开始接受传入的连接请求。这些连接请求会被放置在一个连接请求队列中,等待服务器进程使用 accept() 函数来接受这些请求并建立连接。
注意事项:
backlog 参数指定了连接请求队列的最大长度。如果队列已满,则新的连接请求将被拒绝。实际允许的队列长度可能会受到系统限制。listen() 之后,通常需要调用 accept() 函数来接受连接请求并建立连接。示例:
- #include <sys/types.h>
- #include <sys/socket.h>
-
- int main() {
- int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sockfd == -1) {
- // 处理创建套接字失败的情况
- return -1;
- }
- // 套接字创建成功,可以进行后续操作
-
- if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
- // 处理绑定地址和端口失败的情况
- return -1;
- }
-
- if (listen(sockfd, 10) == -1) {
- // 处理监听套接字失败的情况
- return -1;
- }
- // 套接字处于监听状态,可以接受连接请求并建立连接
-
- return 0;
- }
-
- /*处理客户端发起的连接,生成新的套接字*/
- int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- -sockfd: 函数socket生成的套接字
- -addr:客户端的地址族信息
- -addrlen:地址族结构体的长度
参数:
sockfd:监听套接字描述符,即之前调用 listen() 函数返回的套接字描述符。addr:指向用于存储客户端地址信息的结构体 sockaddr 的指针,可以为 NULL。addrlen:指向存储客户端地址长度的变量的指针,如果 addr 不为 NULL,则需要将 addrlen 设置为 sizeof(struct sockaddr)。返回值:
accept() 函数时,返回一个新的套接字描述符,用于处理与客户端的连接。accept() 函数失败时,返回 -1 并设置 errno 来表示具体的错误原因。函数功能: accept() 函数用于监听套接字上接受传入的连接请求,并创建一个新的套接字来处理与客户端的连接。该新的套接字用于与客户端进行通信。在调用 accept() 函数之前,需要先使用 socket()、bind() 和 listen() 函数来准备监听套接字。
当有一个连接请求到达监听套接字时,accept() 函数会从连接请求队列中取出一个请求,创建一个新的套接字来处理该连接,并返回新创建的套接字描述符。可以通过新创建的套接字描述符进行与客户端的通信。
如果传入的 addr 不为 NULL,则 accept() 函数会将客户端的地址信息存储在 addr 指向的结构体中。同时,addrlen 也需要传入一个指向存储客户端地址长度的变量的指针。
注意事项:
accept() 函数是一个阻塞调用,当没有连接请求时,它会一直等待,直到有连接请求到达或出现错误才返回。accept() 函数来实现并发处理多个连接请求的功能。示例:
- #include <sys/types.h>
- #include <sys/socket.h>
-
- int main() {
- int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sockfd == -1) {
- // 处理创建套接字失败的情况
- return -1;
- }
- // 套接字创建成功,可以进行后续操作
-
- if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
- // 处理绑定地址和端口失败的情况
- return -1;
- }
-
- if (listen(sockfd, 10) == -1) {
- // 处理监听套接字失败的情况
- return -1;
- }
- // 套接字处于监听状态,可以接受连接请求并建立连接
-
- struct sockaddr_in client_addr;
- socklen_t client_addrlen = sizeof(client_addr);
- int client_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_addrlen);
- if (client_sockfd == -1) {
- // 处理接受连接请求失败的情况
- return -1;
- }
- // 成功接受连接请求,可以使用 client_sockfd 进行与客户端的通信
-
- return 0;
- }
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define PORT 5001
- #define BACKLOG 5
-
- int main(int argc, char *argv[])
- {
- int fd, newfd;
- char buf[BUFSIZ] = {}; //BUFSIZ 8142
- struct sockaddr_in addr;
- /*创建套接字*/
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if(fd < 0){
- perror("socket");
- exit(0);
- }
- addr.sin_family = AF_INET;
- addr.sin_port = htons(PORT);
- addr.sin_addr.s_addr = 0;
- /*绑定通信结构体*/
- if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
- perror("bind");
- exit(0);
- }
- /*设置套接字为监听模式*/
- if(listen(fd, BACKLOG) == -1){
- perror("listen");
- exit(0);
- }
- /*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/
- newfd = accept(fd, NULL, NULL);
- if(newfd < 0){
- perror("accept");
- exit(0);
- }
- printf("BUFSIZ = %d\n", BUFSIZ);
- read(newfd, buf, BUFSIZ);
- printf("buf = %s\n", buf);
- close(fd);
- return 0;
- }
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define PORT 5001
- #define BACKLOG 5
- #define STR "Hello World!"
-
- int main(int argc, char *argv[])
- {
- int fd;
- struct sockaddr_in addr;
- /*创建套接字*/
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if(fd < 0){
- perror("socket");
- exit(0);
- }
- addr.sin_family = AF_INET;
- addr.sin_port = htons(PORT);
- addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- /*向服务端发起连接请求*/
- if(connect(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
- perror("connect");
- exit(0);
- }
- write(fd, STR, sizeof(STR) );
- printf("STR = %s\n", STR);
- close(fd);
- return 0;
- }
服务端
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define BACKLOG 5
-
- int main(int argc, char *argv[])
- {
- int fd, newfd, ret;
- char buf[BUFSIZ] = {}; //BUFSIZ 8142
- struct sockaddr_in addr;
-
- if(argc < 3){
- fprintf(stderr, "%s
\n" , argv[0]); - exit(0);
- }
-
- /*创建套接字*/
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if(fd < 0){
- perror("socket");
- exit(0);
- }
- addr.sin_family = AF_INET;
- addr.sin_port = htons( atoi(argv[2]) );
- if ( inet_aton(argv[1], &addr.sin_addr) == 0) {
- fprintf(stderr, "Invalid address\n");
- exit(EXIT_FAILURE);
- }
-
- /*绑定通信结构体*/
- if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
- perror("bind");
- exit(0);
- }
- /*设置套接字为监听模式*/
- if(listen(fd, BACKLOG) == -1){
- perror("listen");
- exit(0);
- }
- /*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/
- newfd = accept(fd, NULL, NULL);
- if(newfd < 0){
- perror("accept");
- exit(0);
- }
- while(1){
- memset(buf, 0, BUFSIZ);
- ret = read(newfd, buf, BUFSIZ);
- if(ret < 0)
- {
- perror("read");
- exit(0);
- }
- else if(ret == 0)
- break;
- else
- printf("buf = %s\n", buf);
- }
- close(newfd);
- close(fd);
- return 0;
- }
客户端
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define BACKLOG 5
-
- int main(int argc, char *argv[])
- {
- int fd;
- struct sockaddr_in addr;
- char buf[BUFSIZ] = {};
-
- if(argc < 3){
- fprintf(stderr, "%s
\n" , argv[0]); - exit(0);
- }
-
- /*创建套接字*/
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if(fd < 0){
- perror("socket");
- exit(0);
- }
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons( atoi(argv[2]) );
- if ( inet_aton(argv[1], &addr.sin_addr) == 0) {
- fprintf(stderr, "Invalid address\n");
- exit(EXIT_FAILURE);
- }
-
- /*向服务端发起连接请求*/
- if(connect(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
- perror("connect");
- exit(0);
- }
- while(1){
- printf("Input->");
- fgets(buf, BUFSIZ, stdin);
- write(fd, buf, strlen(buf) );
- }
- close(fd);
- return 0;
- }
实现TCP通信代码,并使用Makefile进行编译。提交代码和完成通信的截图
client
- #include
- #include
- #include
- #include
- #include
-
- #define CLIENT_MAX_NUM 5
-
- int main(int argc, char * argv[])
- {
- int clientfd;
- struct sockaddr_in server_addr;
- char buf[BUFSIZ];
- int ret;
-
- if( argc < 3)
- {
- printf("%s
\n" ,argv[0]); - return 0;
- }
-
- clientfd = socket(AF_INET, SOCK_STREAM,0);
- if(clientfd == -1)
- {
- perror("socket");
- return 0;
- }
-
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons( atoi(argv[2]) ) ;
- if( inet_aton(argv[1], &server_addr.sin_addr) == 0)
- {
- printf("Invalid address:%s\n",argv[1]);
- return 0;
- }
-
- if(connect(clientfd, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1)
- {
- perror("connect");
- return 0;
- }
-
-
- while(1)
- {
- printf(">");
- fgets(buf, BUFSIZ, stdin);
- write(clientfd, buf, strlen(buf));
- }
- close(clientfd);
- return 0;
- }
server
- #include
- #include
- #include
- #include
- #include
-
- #define CLIENT_MAX_NUM 5
-
- int main(int argc, char * argv[])
- {
- int sockfd, clientfd;
- struct sockaddr_in server_addr;
- char buf[BUFSIZ];
- int ret;
-
- if( argc < 3)
- {
- printf("%s
\n" ,argv[0]); - return 0;
- }
-
- sockfd = socket(AF_INET, SOCK_STREAM,0);
- if(sockfd == -1)
- {
- perror("socket");
- return 0;
- }
-
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons( atoi(argv[2]) ) ;
- if( inet_aton(argv[1], &server_addr.sin_addr) == 0)
- {
- printf("Invalid address:%s\n",argv[1]);
- return 0;
- }
-
- if(bind(sockfd, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1)
- {
- perror("bind");
- return 0;
- }
-
- if(listen(sockfd, CLIENT_MAX_NUM) == -1)
- {
- perror("listen");
- return 0;
- }
-
- clientfd = accept(sockfd, NULL, NULL);
- if( clientfd == -1)
- {
- perror("accept");
- return 0;
- }
-
- while(1)
- {
- memset(buf, 0, BUFSIZ);
- ret = read(clientfd, buf, BUFSIZ);
- if(ret < 0)
- {
- perror("read");
- return 0;
- }
- else if( ret == 0 )
- {
- break;
- }
- else
- {
- printf("buf = %s\n", buf);
- }
- }
- close(clientfd);
- close(sockfd);
- return 0;
- }
makefile
- CC=gcc
- CFLAGS=-Wall
- all:tcp_client tcp_server
-
- clean:
- rm tcp_server tcp_client