Linux网络编程学习总结
Linux网络编程学习总结 ................................................................................................................. 1
目录 .................................................................................................................................................. 3
一、socket结构 ............................................................................................................................... 3
1. struct sockaddr通用套接字 ................................................................................................ 3
2. struct sockaddr_in 实际使用套接字................................................................................... 3
二、socket类型 ............................................................................................................................... 4
1. SOCK_STREAM ...................................................................................................................... 4
2. SOCK_DGRAM ....................................................................................................................... 4
3. SOCK_RAM ............................................................................................................................ 4
三、 TCP网络编程架构.................................................................................................................. 4
1. 服务器客户端交互 .............................................................................................................. 4
2. 服务器函数 ......................................................................................................................... 5
1) socket().......................................................................................................................... 5
2) bind() ............................................................................................................................. 6
3) listen() ........................................................................................................................... 7
4) accept() ......................................................................................................................... 7
5) send()/write() ................................................................................................................ 8
6) recv()/read() .................................................................................................................. 9
7) close() ............................................................................................................................ 9
3. 客户端函数 ....................................................................................................................... 10
1) socket()........................................................................................................................ 10
2) connect() ..................................................................................................................... 10
3) send() .......................................................................................................................... 10
4) recv() ........................................................................................................................... 11
5) close() .......................................................................................................................... 11
四、 服务器客户端的例子 ........................................................................................................... 11
1. 服务器接收/发送 .............................................................................................................. 11
2. 客户端接收/发送 .............................................................................................................. 12
3. Makefile编写 ..................................................................................................................... 14
4. 线程 ................................................................................................................................... 14
1) 线程创建pthread_create() ....................................................................................... 14
2) pthread_join() ............................................................................................................. 15
3) pthread_exit() ............................................................................................................. 15
5. 使用到的其他函数 ............................................................................................................ 16
1) htonl()/htons() ............................................................................................................ 16
2) fork() ........................................................................................................................... 16
3) inet_pton() .................................................................................................................. 16
目录
学习Linux网络编程也有一段时间,在吕同学和乔老师的帮助下写了一个服务器与客户端之间收发消息的例子,下面就主要用到的知识点作一回顾和总结。
一、socket结构
1. struct sockaddr通用套接字
struct sockaddr
{
u_short sa_family; //协议簇
char sa_data[14]; //14字节的特定协议地址
}
2. struct sockaddr_in 实际使用套接字
struct sockaddr_in
{
u8
u8
u16 sin_len; /*struct sockaddr_in 的长度16*/ sin_family;/*AF_INET*/ sin_port;/*16位端口号*/
sin_addr;/*IP地址32位*/ struct in_addr
char
} sin_zero[8];
struct in_addr结构:
struct in_addr
{
u32
} s_addr; //32位IP地址,网络字节序
二、socket类型
1. SOCK_STREAM:流式套接字可以提供可靠的、面向连接的
通讯流,使用TCP协议。
2. SOCK_DGRAM:数据报套接字定义了一种无连接的服务,数
据报通过相互独立的报文进行传输,是无序的并且不保证可靠,使用UDP协议。
3. SOCK_RAM:原始套接字使用IP协议,用于新的网络协议的
测试。
三、TCP网络编程架构
1. 服务器客户端交互
图一
2. 服务器函数
1) socket()
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
创建一个socket,返回值:非负数-----创建成功,-1-------创建失败
family:协议簇
type:套接字的类型:是流式套接字?数据报套接字还是原始套接字
protocol: 套接口所用的协议。如调用者不想指定,可用 0
其返回值:调用成功就返回新创建的套接字的描述符,如果失败就返回INVALID_SOCKET。
绑定一个地址端口bind()
int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);
用于绑定Ip地址和端口号到socket
socket:是一个套接字。
address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。
address_len:确定缓冲区的长度。
其返回值:如果函数执行成功,返回值为0,否则为SOCKET_ERROR。
2) bind()
int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);
该函数用于绑定IP地址和端口号到socket。
sockfd:是一个套接字;
myaddr:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号;
addr_len:确定缓冲区的长度;
如果函数执行成功,返回值为0,否则为SOCKET_ERROR。
3) listen()
int listen(int sockfd, int backlog);
listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。
listen函数在调用bind之后-调用accept之前调用。 sockfd:套接字描述符
backlog:连接请求队列(queue of pending connections)的最大长度(一般由2到4)。用SOMAXCONN则由系统确定。 其返回值:无错误,返回0, 否则,返回SOCKET ERROR,可以调用函数WSAGetLastError取得错误代码。
4) accept()
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
该函数用来等待来自客户端的socket连接请求。
sockfd:套接字描述符
addr:指向结构体sockaddr的指针。
addrlen: addr参数指向的内存空间的长度。
其返回值:成功返回新套接字描述符;失败返回错误信息 。
5) send()/write()
send()
size_t send ( int s , const void *msg , size_t len , int flags); 该函数用来发送数据
s:发送端套接字描述符;
msg:一个存放应用程式要发送数据的缓冲区;
len:实际要发送的字节数;
flags:一般为0
其返回值:成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。
write()
int write(int fd,void *buf,size_t nbyte);
write函数将buf中的length字节内容写入文件描述符fd。 fd:要写的套接字
buf:存放要写的数据的缓冲区
nbyte:缓冲区长度
返回值:成功返回实际所写的字节数,失败时返回-1
6) recv()/read()
recv()
int recv( int s, coid* msgbuf, size_t len, int flags);
该函数用于接收数据
s:一个标识已连接套接口的描述字。
msgbuf:用于接收数据的缓冲区。
len:缓冲区长度。
flags:指定调用方式。
read()
size_t read(int fd,void *buf,size_t nbyte);
该函数用于读取fd中的内容。
fd:要读的套接字。
buf:存放数据的缓冲区。
nbyte:缓冲区长度。
返回值:读成功时:read返回实际所读的字节数 返回的值是0:表示已经读到文件的结束了
小于0:表示出现了错误。如果错误为EINTR说明读是由 中断引起的,如果是ECONNREST表示网络连接出了问题。
7) close()
int close(int fd);
关闭socket连接,内核会释放相关资源,关闭之后则不能 使用该文件描述符进行读写操作。
3. 客户端函数
1) socket()
同服务器socket()相同。
2) connect() int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
该函数用于与服务器建立连接
sockfd:套接字描述符
serv_addr:指向数据结构sockaddr的指针,其中包括目的端口和IP地址
addrlen:参数二sockaddr的长度。(可以通过sizeof(struct sockaddr)获得 )
其返回值:成功则返回0,失败返回-1。
3) send()
同服务器send()相同。
4) recv()
同服务器recv()相同。
5) close()
四、服务器客户端的例子
1. 服务器接收/发送
/*process server recv*/
void *process_server_recv(void *p) {
for(;;) { } size = read(sock_client, buffer, 1024); if(size > 0) { } write(1, buffer, size);/*写到标准输出*/ int sock_client = (int)p; ssize_t size = 0; char buffer[1024];
}
/*process server send*/
void process_server_send(int sock_client) {
} ssize_t size = 0; char buffer[1024]; for(;;) { } size = read(0, buffer, 1024);/*从标准输入读*/ if(size == 0) { } write(sock_client, buffer, size);/*发送给客户端*/ return;
2. 客户端接收/发送
/*process client recv*/
void *process_client_recv(void *p) {
int sock_server = (int)p;
} ssize_t size = 0; char buffer[1024]; for(;;) { } size = read(sock_server, buffer, 1024); if(size == 0) { } write(1, buffer, size); return;
/*process client send*/
void process_client_send(int sock_server) {
ssize_t size = 0; char buffer[1024]; for(;;) { /*from stdinput read data to buffer*/ size = read(0, buffer, 1024); if(size > 0)
} } { write(sock_server, buffer, size);/*send to server*/ }
3. Makefile编写
CC = gcc
all:client server
client:client.o
$(CC) -o client client.o -lpthread
server:server.o
$(CC) -o server server.o -lpthread
clean:
rm -f client server *.o
4. 线程
1) 线程创建pthread_create()
pthread_t pth;
int pthread_create(pthread_t *thread, const pthtead_attr_t *attr, void *(*start_routine)(void *),void *arg);
第一个参数是thread的标识符,是一个pthread_t的变量;
第二个参数是thread的属性(如线程栈的大小),NULL为默认参数; 第三个参数是函数指针,就是该线程要运行的代码,即线程在源代码上的表现形式就是一个函数;
第四个参数是传递给thread的参数。
thread对应的函数体
void *th(void *p);
返回类型必须是一个void类型的指针,参数也必须是一个void类型指针。
2) pthread_join()
int pthread_join(pthread_t thread, void **retval);
函数pthread_join用来等待一个线程的结束。
thread: 线程标识符,即线程ID,标识唯一线程。retval: 用户定义的指针,用来存储被等待线程的返回值。
返回值 : 0代表成功。 失败,返回的则是错误号。
3) pthread_exit()
void pthread_exit(void* retval);
线程通过调用pthread_exit函数终止执行,就如同进程在结束时调用exit函数一样。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。
5. 使用到的其他函数
1) htonl()/htons()
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
将主机数转换成无符号长整型的网络字节顺序。本函数将一个 32位数从主机字节顺序转换成网络字节顺序。
uint16_t htons(uint16_t hostshort);
将主机的无符号短整形数转换成网络字节顺序。hostshort:主 机字节顺序表达的16位数。
2) fork()
pid_t fork(void);
pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中。
返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1
3) inet_pton()
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
功能:IP地址转换函数,可以在将IP地址在“点分十进制”和“二进制整数”之间转换。
这个函数转换字符串到网络地址,第一个参数af是地址簇,第二个参数*src是来源地址,第三个参数* dst接收转换后的数据。 af = AF_INET
src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址转换为in_addr的结构体,并复制在*dst中。