文章目录
TCP网络编程示意总图
网络编程相关API
创建套接字——socket()
int socket(int domain, int type, int protocol);
- 头文件
#include <sys/types.h>
#include <sys/socket.h> - domain
Name | Purpose | Man page |
---|---|---|
AF_INET | IPv4 Internet protocols | ip(7) |
AF_INET6 | IPv6 Internet protocols | ipv6(7) |
AF_UNIX / AF_LOCAL | Local communication | unix(7) |
- type
Name | Purpose |
---|---|
SOCK_STREAM | 流式套接字,唯一对应着TCP |
SOCK_DGRAM | 数据报套接字,唯一对应着UDP |
SOCK_RAW | 原始套接字 |
-
protocol
一般填0,原始套接字编程时需要填充 -
返回值
成功时,将返回新套接字的文件描述符。
错误返回错误-1,并设置errno。
绑定本机地址和端口——bind()
int bind(int sockfd, const struct sockaddr addr, socklen_t addrlen);
-
头文件
#include <sys/types.h>
#include <sys/socket.h> -
sockfd是由socket()返回的文件描述符
-
addr是指向 struct sockaddr的结构体变量的地址
-
addrlen 地址长度
-
返回值
成功时,将返回0。
错误返回错误-1,并设置errno。
struct sockaddr是通用结构体,对于不同的协议有不同的结构体
AF_INET对应的struct sockaddr_in结构体:
地址结构的一般用法
1)定义一个struct sockaddr_in类型的变量并清空
struct sockaddr_in myaddr;
memset(&myaddr, 0, sizeof(myaddr));
2)填充地址信息
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(8888);
myaddr.sin_addr.s_addr = inet_addr("192.168.1.100");
3)将该变量强制转换为struct sockaddr类型在函数中使用
bind(lsockfd, (struct sockaddr*)(&myaddr), sizeof(myaddr));
地址转换函数
1)unsigned long inet_addr(char address);
address是以‘\0’结尾的点分IPV4字符串。该函数返回32位的地址。如果字符串包含的不是合法的IP地址,则函数返回-1.
例如:
struct in_addr addr;
addr.s_addr = inet_addr("192.168.1.100");
2)char inet_ntoa(struct in_addr address);
address是IPv4结构地址,函数返回指向包含点分IP地址的静态存储区字符指针。如果错误则返回NULL
建立连接——connect()
int connect(int sockfd, const struct sockaddr addr, socklen_t addrlen);
-
头文件
#include <sys/types.h>
#include <sys/socket.h> -
sockfd是由socket()返回的文件描述符
-
addr服务端的地址信息
-
addrlen 地址长度
-
返回值
成功时,将返回0。
错误返回错误-1,并设置errno。 -
connect()是客户端使用的系统调用
设置监听端口——listen()
int listen(int sockfd, int backlog);
- 头文件
#include <sys/types.h>
#include <sys/socket.h> - sockfd监听连接的套接字
- backlog
1)指定了正在等待连接的最大队列长度,它的作用在于处理可能同时出现的几个连接请求。
2)DoS(拒绝服务)攻击即利用了这个原理,非法的连接占用了全部的连接数,造成正常的连接请求被拒绝。 - 返回值
成功时,将返回0。
错误返回错误-1,并设置errno。 - 完成listen()调用后,socket()变成了监听socket(listeing socket),即由主动socket变成了被动socket。
接受TCP连接——accept()
int accept(int sockfd, struct sockaddr * addr, socklen_t addrlen) ;
-
头文件
#include <sys/types.h>
#include <sys/socket.h> -
sockfd: 监听套接字
-
addr:对方地址
-
addrlen:地址长度
-
返回值
成功时返回已经建立好连接的套接字。
失败返回-1。
listen()和accept()是TCP服务端使用的函数。
数据接受——recv()、read()、recvfrom()
recv()函数
ssize_t recv(int sockfd, void buf, size_t len, int flags);
-
头文件
#include <sys/types.h>
#include <sys/socket.h> -
buf:发送缓冲区首地址
-
len:发送的字节数
-
flags:接受方式(通常为0)
-
返回值
成功时返回实际接收的字节数
失败返回-1,并设置errno
read()函数
ssize_t read(int fd, void buf, size_t count);
recvfrom()函数
ssize_t recvfrom(int sockfd, void buf, size_t len, int flags, struct sockaddr src_addr, socklen_t addrlen);
数据发送——send()、write()、sendto()
send()函数
ssize_t send(int socket, const void buffer, size_t length, int flags);
该函数于recv()组合使用
write()函数
ssize_t write(int fd, const void buf, size_t count);
该函数于read()组合使用
sendto()函数
ssize_t recvfrom(int socket, void buffer, size_t length, int flags, struct sockaddr address, socklen_t address_len);
该函数于recvfrom()组合使用。
关闭套接字——close()、shutdown()
1)int close(int fd);
功能:关闭双向通信
2) int shutdown(int sockfd , int howto);
- 功能
TCP连接是双向的(是可读写的),当我们使用close时,会把读写通道都关闭,有时 侯我们希望只关闭一个方向,这个时候我们可以使用shutdown。 - howto:
SHUT_RD,further receptions will be disallowed. 禁止接收
SHUT_WR, further transmissions will be disallowed. 禁止传输
SHUT_RDWR, further receptions and transmissions will be disallowed.禁止接收和传输
程序框架
TCP循环服务器模型
TCP循环服务器一次只能处理一个客户端的请求.只有在这个客户的所有请求都满足后, 服务器才可以继续后面的请求.这样如果有一个客户端占住服务器不放时,其它的客户机都不能工作了.因此,TCP服务器一般很少用循环服务器模型的.
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <stdlib.h>
#include<string.h>
int main(int argc, const char *argv[])
{
int sockfd;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket");
exit(-1);
}
struct sockaddr_in myaddr;
memset(&myaddr,0,sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(8888);
myaddr.sin_addr.s_addr = inet_addr("192.168.9.10");
bind(sockfd,(struct sockaddr*)(&myaddr),sizeof(myaddr));
listen(sockfd,1);
struct sockaddr_in caddr;
int cfd;
socklen_t len=sizeof(caddr);
char buf[20];
while(1)
{
cfd=accept(sockfd,(struct sockaddr*)(&caddr),&len);
read(cfd,buf,20);
printf("%s\n",buf);
close(cfd);
}
close(sockfd);
return 0;
}
TCP多进程并发服务器
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
void signal_handler(int signo)
{
if(sogno == SIGCHLD)
{
wait(NULL);
}
}
int main(int argc, const char *argv[])
{
int sfd;
signal(SIGCHLD,signal_handler);
sfd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in myaddr;
memset(&myaddr,0,sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(8888);
myaddr.sin_addr.s_addr = inet_addr("192.168.9.10");
bind(sfd,(struct sockaddr *)(&myaddr),sizeof(myaddr));
listen(sfd,10);
struct sockaddr_in caddr;
socklen_t len = sizeof(caddr);
int cfd;
char buf[20];
char buffer[]={"stop"};
pid_t pid;
while(1)
{
cfd=accept(sfd,(struct sockaddr*)(&caddr),&len);
if(cfd == -1)
{
perror("accept");
exit(-1);
}
pid=fork();
if(pid==0)
{
close(sfd);
printf("client is connect ,sockfd is %d\n",cfd);
while(1)
{
read(cfd,buf,20);
if(strcmp(buf,buffer) == 0)
{
printf("client is quit,sockfd is %d !\n",cfd);
break;
}
printf("%s\n",buf);
}
exit(0);
}
close(cfd);
}
close(sfd);
return 0;
}
TCP多线程并发服务器
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
void pthread_handle(void * arg);
int main(int argc, const char *argv[])
{
int sfd;
sfd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in myaddr;
myaddr.sin_family=AF_INET;
myaddr.sin_port = htons(8888);
myaddr.sin_addr.s_addr = inet_addr("192.168.9.10");
bind(sfd,(struct sockaddr*)(&myaddr),sizeof(myaddr));
listen(sfd,10);
struct sockaddr_in caddr;
socklen_t len = sizeof(caddr);
int cfd;
pthread_t pfd;
while(1)
{
cfd=accept(sfd,(struct sockaddr*)(&caddr),&len);
if(cfd == -1)
{
perror("accept");
exit(0);
}
char ipv4_addr[16];
if(!inet_ntop(AF_INET,(void *)&caddr.sin_addr,ipv4_addr,sizeof(caddr)))
{
perror("inet_ntop");
exit(1);
}
printf("client is connect,addr is %s \n",ipv4_addr);
pthread_create(&pfd,NULL,pthread_handle,(void*)&cfd);
pthread_join(pfd,NULL);
}
close(sfd);
return 0;
}
void pthread_handle(void * arg)
{
char buf[20];
char buffer[]="stop";
int cfd = *(int *)arg;
while(1)
{
read(cfd,buf,20);
printf("%s\n",buf);
if(strcmp(buf,buffer)==0)
{
printf("client is quit,cfd is %d\n",cfd);
break;
}
}
close(cfd);
}