网络编程API

网络编程

Posted by Gu on 2022-12-01
Estimated Reading Time 9 Minutes
Words 2.3k In Total

网络编程API

套接字

#include <sys/socket.h>

iovec结构体

1
2
3
4
struct iovec {
void* iov_base; //缓冲地址
size_t iov_len; //缓冲大小
}

TCP

函数 功能
int socket(int domain, int type, int protocol); 创建套接字,成功返回文件描述符,失败返回-1
int bind(int sockfd , struct sockaddr *myaddr, socklen addrlen); 绑定套接字ip与端口,成功返回0,失败返回-1
int listen(int sockfd , int backlog); 设置监听,成功返回0,失败返回-1
int accept(int sockfd, struct sockaddr *addr… socklen_t *addrlen); 接收连接,成功返回文件描述符,失败返回-1
int connect(int sockfdJ struct sockaddr *serv_addr, socklen_t addrlen); 发起连接,成功返回0,失败返回-1
sslze_t send(int sockfd, const void * buf, size_t nbytes, int flags); 发送数据,成功返回发送字节数,失败返回-1
ssize_t recv(int sock void * buf, size_t nbytes, int flags); 接受数据,成功返回接受字节数,失败返回-1
#include <sys/uio.h>
ssize_t writev(int filedes const struct iovec * iov, int iovcnt);
多个地方整合发送数据,成功返回发送字节数,失败返回-1
#include <sys/unio.h>
ssize_t readv(int filedes, const struct iovec * iov, int iovcnt);
多个地方整合接收数据,成功返回发送字节数,失败返回-1
#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);
在两个文件描述符间零拷贝发送数据,只在内核有拷贝

Nagle算法开启后,TCP收到ACK后才会发送下一个数据包,可以减少网络中因为发送小数据产生的数据包数量。

大文件数据传输禁用Nagle算法,因为会在装满缓冲时传输数据包,并不会增加数据包的数量,还会连续传输,提高传输速度。

TCP_NODELAY可以设置是否开启Nagle算法。

UDP

函数 功能
ssize_t sendto(int sock, void *buff, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen); 发送消息给指定地址的主机,成功返回传输的字节数,失败返回-1
ssize-t ecvfrom(int sock, void *buff, size_t nbytes, int flags, struct sockaddr * from, socklen_t *addrlen); 接受指消息,将主机地址保存在from,成功返回接收的字节数,失败返回-1
  • UDP套接字调用connect并不意味着要和对方UDP套接字连接,只是向UDP套接字注册目标IP和端口信息。这样UDP套接字也可以使用read和write来发送和接收数据。
  • UDP存在数据边界,TCP不存在。因此UDP调用多少次sendto发送,就要调用多少次recvfrom。

套接字设置

函数 功能
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen); 获取套接字属性,成功返回0,失败返回-1
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen); 设置套接字属性,成功返回0,失败返回-1

文件操作

函数 功能
#include <sys/types.h>
#include <sys/stat.h>
#inlcude <fcntl.h>
int open(const char *path int flag);
打开文件,成功返回文件描述符,失败返回-1
#include <unistd.h>
int close(int fd);
关闭文件,成功返回0,失败返回-1
#include <unistd.h>
ssize_t write(int fd, const void* buf, size_t nbytes);
成功返回写入的字节数,失败返回-1
#include <unistd.h>
ssize_t read(int fd, void* buf, size_t nbytes);
成功返回接受的字节数(遇到文件尾返回0),失败返回-1

字节序转换

#include <arpa/inet.h>

函数 功能
unsigned short htons(unsigned short); (端口转换)short类型主机序转换为网络序
unsigned short ntohs(unsîgned short); (端口转换)short类型网络序转换为主机序
unsigned long hton1(unsigned long); (ip转换)long类型主机序转换为网络序
unsigned long ntohl(unsigned long); (ip转换)long类型网络序转换为主机序
in_addr_ t inet_addr(const char * string); 将字符串ip地址转换为网络序,成功返回32位大端序整数型值,失败返回INADDR_NONE
int inet_aton(const char * string) struct in_addr * addr); 将字符串ip地址转换为网络序,成功返回1,失败返回0
char* inet_ntoa(struct in_addr adr) ; 将网络序ip转换为字符串,成功返回字符串地址,失败返回-1
  • inet_addr得到的结果仍需要手动设置到in_addr结构体里面;而inet_aton直接就转换完设置进去。
  • INADDR_ANY表示任意ip地址,这样内核会在连接时候选择ip地址。

ip与域名之间的转换

#include <netdb.h>

hostent结构体

1
2
3
4
5
6
7
struct hostent {
cha r * h_name; //official name
char ** h_aliases; //alias list
int h_addrtype; // host address type
int h_length; // address length
char ** h_addr_list; // address list
}
函数 功能
struct hostent * gethostbyname(const char* hostname); 域名转换为ip,成功返回结构体指针,失败返回NULL
struct hostent * gethostbyaddr(const char * addr, socklen_t len, int family); ip转换为域名,成功返回结构体指针,失败返回NULL

进程操作

僵尸子进程

函数 功能
#include <unistd.h>
pid_t fork(void);
创建子进程,成功返回进程id(父进程返回子进程id,子进程返回0),失败返回-1
#include <sys/wait.h>
pid_t wait(int * statloc);
等待回收子进程资源,成功返回子进程pid,失败返回-1。
可以使用WIFEXITED(*statloc)判断子进程是否异常退出,true表示正常终止。
WEXITSTATUS(*statloc)返回子进程的返回值。
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int * statloc, int options);
等待回收指定子进程资源,成功返回子进程pid,失败返回-1。
pid表示想要回收的子进程,为-1时同wait函数一样,回收任意子进程。
若将options设置为WNOHANG,则没有终止的子进程也不会陷入阻塞。

信号处理

发生信号时候,将唤醒由于调用sleep函数而进入阻塞转台的进程。进程一旦唤醒,就不会进入阻塞。

sigaction结构体

1
2
3
4
5
struct sigaction {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
}
函数 功能
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
这样写好理解点:
void (*)(int) signal(int signo, void (*func)(int));
设置信号处理函数;
第一个参数是所要处理的信号,第二个参数是处理该信号的函数指针。
返回类型是函数指针。
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
设置定时发生SIGALRM;
返回0或者以秒为单位的距SIGALRM信号发生所剩时间。
如果参数传递为0,则取消之前的所有定时;
如果添加处理函数,则会终止进程。
#include <signal.h>
int sigaction(int signo, const struct sigaction * act, struct sigaction * oldact) ;
设置信号集,成功返回0,失败返回-1

管道通信

管道使用pipe函数,fork出进程以后,关闭对应读端和写端即可对管道进行读写,若不关闭对应的端,则有可能自己写的自己读;

管道是单向的。

1
2
#include <unistd.h>
int pipe(int filedes[2]);

f[0] 是读端,f[1] 是写端。

多线程操作

#include <pthread.h>

函数 功能
int pthread_create( pthread_t * thread, const pthread_attr_t * attr, void * (* start_routine)(void * ), void *arg); 创建线程,成功返回0,失败返回错误码
int pthread_join(pthread_t thread, void ** retval); 阻塞等待指定线程终止,参数是线程退出的信息,成功返回0,失败返回错误码
void pthread_exit(void* retval); 线程退出,不会失败
int pthread_cancel(pthread_t thread) 异常终止某个线程,成功返回0,失败返回错误码;
int pthread_setcancelstate(int state, int* oldstate);
int pthread_setcanceltype(int type, int* oldtype);
接收到取消请求的目标线程可以通过设置取消状态和类型来决定是否被取消以及如何取消。

线程锁与信号量

信号量

#include <semaphore.h>

以下函数成功返回0,失败返回-1,并设置errno错误码。

函数 功能
int sem_init(sem_t* sem, int pshred, unsigned int value); 初始化信号量,value是信号量初始值
int sem_destroy(sem_t* sem); 销毁信号量
int sem_wait(sem_t* sem); P操作,将信号量值-1
int sem_trywait(sem_t* sem); 不阻塞的P操作,成功返回0,失败返回-1,并设置errno为EAGAIN
int sem_post(sem_t* sem); V操作,将信号量+1,若有线程阻塞在该信号量,则唤醒一个

互斥锁

#include <pthread.h>

以下函数成功返回0,失败返回错误码。

函数 功能
int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexaddr_t* mutex_attr); 初始化互斥锁
int pthread_mutex_destroy(pthread_mutex_t* mutex); 销毁互斥锁
int pthread_mutex_lock(pthread_mutex_t* mutex); 加锁
int pthread_mutex_trylock(pthread_mutex_t* mutex); 尝试解锁
int pthread_mutex_unlock(pthread_mutex_t* mutex); 释放锁

条件变量

#include <pthread.h>

以下函数成功返回0,失败返回错误码。

函数 功能
int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* cond_attr); 初始化条件变量
int pthread_cond_destroy(pthread_cond_t* cond); 销毁条件变量,销毁一个正在被等待的条件变量将失败并返回EBUSY
int pthread_cond_broadcast(pthread_cond_t* cond); 广播唤醒所有等待该条件变量的线程
int pthread_cond_signal(pthread_cond_t* cond); 唤醒一个等待该条件变量的线程
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex); 用于等待目标条件变量,mutex参数用于保护条件变量的互斥锁

pthread_cond_wait简称为wait,方便以下书写:

wait调用前,必须保证mutex已经加锁,wait函数执行时,将线程放入条件变量的等待队列中,然后解锁mutex,此时wait函数未返回。

当wait函数返回时候,会将mutex再次加锁。


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !