Linux网络编程——TCP服务器
2017-08-17 08:57
155 查看
学习笔记,小白可以相互学习,大佬看到能告诉咱理解不对的地方就好了。
while(1) {
2.connect向服务器请求连接,并且建立连接
while(1)
{
3.读写数据:write/read(具体的操作)
}
4close,关闭
socket
2.bind()绑定服务器的IP地址和端口号,注意(IP地址本机的IP地址)
bind
3.connect()客户端使用的系统调用
connect
4.listen()启动服务器,启动监听。启动监听之后,套接字由主动变为被动
listen
5.accept()等待客户端的连接请求,如果没有连接请求则等待,如果有连接请求,则建立连接
socket
6.send()
send
7.recv()
recv
read()write()可以取代recv()send()
/***************服务器server.c********************************/
/******************客户端client.c**************************************/
//***********makefile******************
socket();
bind();
listen();
while(1)
{
accepr();
while(1)
{
write();/read();
}
close();
}
使用signal() 和waitpid()函数对进程进行收尸
1.TCP服务器流程
1.socket,创建服务器(创建socket套接字)
2.bind,设置服务器的IP地址和端口号(将socket和服务器的IP地址和端口号进行绑定)
3.listen,启动监听(启动服务器)
4. accept,等待服务器的连接请求(如果没有连接请求则等待,如果有连接请求,则建立连接)
while(1) {
5. 读写数据:read/write(具体的操作)
}
6. close关闭
2.TCP客户端流程
1.socket,创建客户端(创建一socket套接字)2.connect向服务器请求连接,并且建立连接
while(1)
{
3.读写数据:write/read(具体的操作)
}
4close,关闭
3.网络编程相关API
1.socket()创建一个通信套接字头文件 | #include<sys/types.h> #include<sys/socket.h> |
原型 | int socket(int domain,int type,int protocol) |
参数 | domain:协议族表示创建通信套接口的作用范围 AF_INET: IPV4 AF_INET6: IPV6 AF_UNIX : 本地多进程之间的通信 type:类型,表示创建的套接字类型 SOCK_STREAM 流式套接字 SOCKDGRAM 数据报套接字 SOCK_RAM 原始套接字 protocol:协议,通常为0(原始套接字时不为0) |
返回值 | 成功:返回新的套接字文件描述符 失败:-1,并设置erron |
头文件 | #include <sys/types.h> #include <sys/socket.h> |
原型 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
参数 | sockfd:套接字文件描述符,同过socket创建 addr:结构体指针,指向的是存储服务器的IP地址和端口号的结构体 通用地址结构:struct sockaddr { sa_family_t sa_family;//地址族协议 char sa_data[14];//存储服务器的IP地址和端口号使用麻烦。 } 专用地址结构: struct sockaddr_in { sa_family_t sin_family; /* 地址族 AF_INET,2byte */ in_port_t sin_port; /* 端口,2byte */ struct in_addr sin_addr; /* ipv4地址 */ char sin_zero[8] //8 byte unsued作为填充 }; struct in_addr { uint32_t s_addr; /* address in network byte order */ } addlen:地址长度,也即是结构体的大小 |
返回值 | 成功:地址长度,也就是结构体大小 失败:-1,并设置errno |
头文件 | #include <sys/types.h> #include <sys/socket.h> |
原型 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
参数 | sockfd:套接字文件描述符,同过socket创建 addr:结构体指针,指向的是存储服务器的IP地址和端口号的结构体 通用地址结构:struct sockaddr { sa_family_t sa_family;//地址族协议 char sa_data[14];//存储服务器的IP地址和端口号使用麻烦。 } 专用地址结构: struct sockaddr_in { sa_family_t sin_family; /* 地址族 AF_INET,2byte */ in_port_t sin_port; /* 端口,2byte */ struct in_addr sin_addr; /* ipv4地址 */ char sin_zero[8] //8 byte unsued作为填充 }; struct in_addr { uint32_t s_addr; /* address in network byte order */ } addlen:地址长度,也即是结构体的大小 |
返回值 | 成功:地址长度,也就是结构体大小 失败:-1,并设置errno |
头文件 | #include<sys/types.h> #include<sys/socket.h> |
原型 | int listen(int sockfd, int backlog); |
参数 | sockfd:套接字文件描述符,通过socket创建之后需要bind backlog:指定处理请求队列的大小。而不是最大连接数 |
返回值 | 成功:返回0 失败:-1,并设置erron |
头文件 | #include<sys/types.h> #include<sys/socket.h> |
原型 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) |
参数 | sockfd:套接字文件描述符,监听套接字 addr: 用来存储客户端的IP地址和端口号 addrlen: 客户端地址所占空间大小。在使用的时候,必须赋初值 |
返回值 | 成功:返回新的套接字文件描述符 失败:-1,并设置erron |
头文件 | #include<sys/types.h> #include<sys/socket.h> |
原型 | ssize_t send(int sockfd, const void *buf, size_t len, int flags) |
参数 | sockfd:套接字文件描述符 buf:发送缓冲区的首地址 len:发送的字节数 flags:发送的方式()通常为0) |
返回值 | 成功:返回发送的字节数 失败:-1,并设置erron |
头文件 | #include<sys/types.h> #include<sys/socket.h> |
原型 | ssize_t recv(int sockfd, void *buf, size_t len, int flags); |
参数 | sockfd:套接字文件描述符 buf:发送缓冲区的首地址 len:发送的字节数 flags:接收的方式()通常为0) |
返回值 | 成功:返回接收的字节数 失败:-1,并设置erron |
/***************服务器server.c********************************/
#include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<netinet/ip.h> #include<string.h> #include<stdlib.h> #include<arpa/inet.h> #include<unistd.h> int main() { int listenfd; int ret; int connfd; char buf[256]; struct sockaddr_in srvaddr; struct sockaddr_in cltaddr; socklen_t addlen; //1.创建服务器(创建socket) listenfd = socket(AF_INET,SOCK_STREAM,0); if(listenfd == -1) { perror("server->socket"); return -1; } printf("creat listenfd = %d success\n",listenfd); //2.设置服务器的IP地址和端口号(绑定本机地址和端口) memset(&srvaddr,0,sizeof(struct sockaddr));//从srvaddr开始后面sizeof()个字节写为0 srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(9999); srvaddr.sin_addr.s_addr = inet_addr("192.168.2.27"); ret = bind(listenfd,(const struct sockaddr *)&srvaddr,sizeof(struct sockaddr)); if(-1 == ret) { perror("server->bind"); return -1; } //3.启动监听(启动服务器) ret = listen(listenfd,0); if(-1 == ret) { perror("server->listen"); return -1; } printf("listen success\n"); //4.等待客户端的连接请求 addlen = sizeof(socklen_t); connfd = accept(listenfd,(struct sockaddr *)&cltaddr,&addlen); if(-1 == connfd) { perror("server->accept"); return -1; } while(1) { //5.读写数据read/write memset(buf,0,sizeof(buf)); ret = read(connfd,buf,sizeof(buf)); if(-1 == ret) { perror("client->read"); return -1; } printf("buf : %s\n",buf); ret = write(connfd,buf,sizeof(buf)); if(-1 == ret) { perror("client->write"); return -1; } } //6.关闭 close(connfd); close(listenfd); return 0; }
/******************客户端client.c**************************************/
#include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<netinet/ip.h> #include<string.h> #include<stdlib.h> #include<arpa/inet.h> #include<unistd.h> int main() { int sockfd; int ret; int connfd; char buf[256]; struct sockaddr_in srvaddr; socklen_t addlen; //1.创建客户端(创建socket) sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd == -1) { perror("client->socket"); return -1; } printf("creat listenfd = %d success\n",sockfd); //2.向服务器请求连接并且建立连接(connect) memset(&srvaddr,0,sizeof(struct sockaddr));//从srvaddr开始后面sizeof()个字节写为0 srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(9999); srvaddr.sin_addr.s_addr = inet_addr("192.168.2.27"); ret = connect(sockfd,(const struct sockaddr *)&srvaddr,sizeof(struct sockaddr)); if(-1 == ret) { perror("client->bind"); return -1; } while(1) { //3.读写数据read/write fgets(buf,sizeof(buf),stdin); ret = write(sockfd,buf,sizeof(buf)); if(-1 == ret) { perror("client->write"); return -1; } printf("buf : %s\n",buf); memset(buf,0,sizeof(buf)); ret = read(sockfd,buf,sizeof(buf)); if(-1 == ret) { perror("client->read"); return -1; } printf("buf : %s\n",buf); if(0 == strncmp(buf,"quit",4)) { printf("quit success\n"); break; } } //4.关闭 close(sockfd); return 0; }
//***********makefile******************
all: gcc server.c -o server gcc client.c -o client
2.TCP循环服务器流程
b400socket();
bind();
listen();
while(1)
{
accepr();
while(1)
{
write();/read();
}
close();
}
3.TCP并发服务器流程
并发服务器的设计思想是服务器接受客户端的连接请求后创建子进程来为客服端服务使用signal() 和waitpid()函数对进程进行收尸
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <signal.h> int client(int connfd) //connfd; { int ret; char buf[256]; while(1) { memset(buf, 0, sizeof(buf)); ret = read(connfd, buf, sizeof(buf)); if (ret == -1) { perror("server->read"); return -1; } else if (ret == 0) { return -1; } printf("buf : %s\n", buf); ret = write(connfd, buf, sizeof(buf)); if (ret == -1) { perror("server->write"); return -1; } } return 0; } void fun(int sig) { printf("client quit\n"); while(waitpid(-1, NULL, WNOHANG) > 0); } int main(int argc, char *argv[]) { int listenfd; int ret; socklen_t addrlen; int connfd; pid_t pid; char buf[256]; struct sockaddr_in srvaddr; struct sockaddr_in cltaddr; pthread_t client_pthread; signal(SIGCHLD, fun); /* 1. 创建服务器(创建一socket套接字);socket */ listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd == -1) { perror("server->socket"); return -1; } printf("create listenfd = %d success\n", listenfd); /* 2. 设置服务器的IP地址和端口号(将socket和服务器的IP地址和端口号进行绑定);bind */ memset(&srvaddr, 0, sizeof(struct sockaddr_in)); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(9999); srvaddr.sin_addr.s_addr = inet_addr("192.168.2.100"); ret = bind(listenfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr)); printf("port : %d\n", ntohs(srvaddr.sin_port)); if (ret == -1) { perror("server->bind"); return -1; } printf("bind success !\n"); /* 3. 启动监听(启动服务器); listen */ ret = listen(listenfd, 1024); if (ret == -1) { perror("server->listen"); return -1; } printf("listen success !\n"); while(1) { /* 4. 等待服务器的连接请求,如果没有连接请求则等待,如果有连接请求,则建立连接; accept */ memset(&cltaddr, 0, sizeof(cltaddr)); addrlen = sizeof(cltaddr); connfd = accept(listenfd, (struct sockaddr *)&cltaddr, &addrlen); if (connfd == -1) { perror("server->accept"); return -1; } printf("connect connfd = %d\n", connfd); printf("IP : %s\n", inet_ntoa(cltaddr.sin_addr)); printf("PORT: %d\n", ntohs(cltaddr.sin_port)); pid_t pid; pid = fork(); if (pid == -1) { perror("fork"); return -1; } else if (pid == 0) { close(listenfd); client(connfd); exit(0); } close(connfd); } close(listenfd); return 0; }
4.采用线程方式实现TCP服务器
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <pthread.h> void * client(void *arg) //connfd; { int connfd; int ret; char buf[256]; connfd = *(int *)arg; while(1) { memset(buf, 0, sizeof(buf)); ret = read(connfd, buf, sizeof(buf)); if (ret == -1) { perror("server->read"); pthread_exit(NULL); } else if (ret == 0) { close(connfd); pthread_exit(NULL); } printf("buf : %s\n", buf); ret = write(connfd, buf, sizeof(buf)); if (ret == -1) { perror("server->write"); pthread_exit(NULL); } } pthread_exit(NULL); } void fun(int sig) { printf("client quit\n"); while(waitpid(-1, NULL, WNOHANG) > 0); } int main(int argc, char *argv[]) { int listenfd; int ret; socklen_t addrlen; int connfd; pid_t pid; char buf[256]; struct sockaddr_in srvaddr; struct sockaddr_in cltaddr; pthread_t client_pthread; /* 1. 创建服务器(创建一socket套接字);socket */ listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd == -1) { perror("server->socket"); return -1; } printf("create listenfd = %d success\n", listenfd); /* 2. 设置服务器的IP地址和端口号(将socket和服务器的IP地址和端口号进行绑定);bind */ memset(&srvaddr, 0, sizeof(struct sockaddr_in)); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(9999); srvaddr.sin_addr.s_addr = inet_addr("192.168.2.100"); ret = bind(listenfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr)); printf("port : %d\n", ntohs(srvaddr.sin_port)); if (ret == -1) { perror("server->bind"); return -1; } printf("bind success !\n"); /* 3. 启动监听(启动服务器); listen */ ret = listen(listenfd, 1024); if (ret == -1) { perror("server->listen"); return -1; } printf("listen success !\n"); while(1) { /* 4. 等待服务器的连接请求,如果没有连接请求则等待,如果有连接请求,则建立连接; accept */ memset(&cltaddr, 0, sizeof(cltaddr)); addrlen = sizeof(cltaddr); connfd = accept(listenfd, (struct sockaddr *)&cltaddr, &addrlen); if (connfd == -1) { perror("server->accept"); return -1; } printf("connect connfd = %d\n", connfd); printf("IP : %s\n", inet_ntoa(cltaddr.sin_addr)); printf("PORT: %d\n", ntohs(cltaddr.sin_port)); /* 创建一个子线程,处理客户端的请求*/ ret = pthread_create(&client_pthread, NULL, client, (void *)&connfd); if (ret != 0) { printf("create client pthread fail\n"); return -1; } printf("create client_pthread = %d success\n", client_pthread); ret = pthread_detach(client_pthread); if (ret != 0) { printf("detach client pthread fail\n"); return -1; } printf("detach cltaddr pthread success\n"); } close(listenfd); return 0; }
相关文章推荐
- Linux网络编程【七】:TCP协议高性能服务器(http)模型之I/O多路转接poll
- Linux网络编程——tcp并发服务器(多线程)
- Linux网络编程 5 - select模式的TCP服务器
- Linux网络编程——tcp并发服务器(poll实现)
- Linux网络编程——tcp并发服务器(poll实现)
- Linux网络编程【五】:TCP协议高性能服务器(http)模型之I/O多路转接select
- Linux网络编程14——tcp、udp迭代服务器
- Linux网络编程:TCP服务器(单进程多用户),使用select方法实现
- Linux网络编程——tcp并发服务器(多进程)
- Linux网络编程——tcp并发服务器(多线程)
- Linux网络编程——tcp并发服务器(epoll实现)
- Linux网络编程——tcp并发服务器(poll实现)
- Linux网络编程——tcp并发服务器(poll实现)
- Linux网络编程——tcp并发服务器(I/O复用之select)
- Linux网络编程--tcp服务器
- Linux网络编程——tcp并发服务器(epoll实现)
- Linux网络编程10——TCP编程之服务器
- Linux网络编程——tcp并发服务器(I/O复用之select
- Linux网络编程:TCP服务器(单进程多用户),使用select方法实现