linux网络编程初探
1.单客户端模式的程序 来源:《Linux程序设计》第4版 15.2节
/*----头文件与变量声明-----------------------------------------------------*/ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> int main() { int sockfd; int len; struct sockaddr_in address; int result; char ch = 'A'; /*--为客户建立一个套接字----------------------------------------------------*/ sockfd = socket(AF_INET, SOCK_STREAM, 0); /*--根据服务器的情况给套接字命名----------------------------------------------*/ address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr("127.0.0.1"); address.sin_port = htons(9734); len = sizeof(address); /*--将我们的套接字连接到服务器的套接字------------------------------------------*/ result = connect(sockfd, (struct sockaddr *)&address, len); if(result == -1){ perror("oops: connection failed"); exit(1); } /*--现在就可以通过sockfd进行读写操作了-----------------------------------------*/ write(sockfd, &ch, 1); read(sockfd, &ch, 1); printf("char from server = %c\n", ch); close(sockfd); exit(0); }
/*-头文件与变量声明--------------------------------------------------------*/ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> int main() { int server_sockfd, client_sockfd; int server_len, client_len; struct sockaddr_in server_address; struct sockaddr_in client_address; /*--删除以前的套接字,为服务器创建一个未命名的套接字-------------------------*/ unlink("server_socket"); server_sockfd = socket(AF_INET, SOCK_STREAM, 0); /*------命名套接字-----------------------------------------------------------*/ server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_port = htons(9734); server_len = sizeof(server_address); bind(server_sockfd, (struct sockaddr *)&server_address, server_len); /*---创建一个连接队列,开始等待客户进行连接----------------------------------*/ listen(server_sockfd, 5); while(1){ char ch; printf("server waiting\n"); /*------接受一个连接---------------------------------------------------------*/ client_len = sizeof(client_address); client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len); /*----对client_sockfd套接字上的客户进行读写操作------------------------------*/ read(client_sockfd, &ch, 1); ch++; write(client_sockfd, &ch, 1); close(client_sockfd); } }
0基础者请将程序拷出,对照下面注释查看
2.编写套接字通信程序的步骤
①socket:创建套接字
-------------------------------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
int socket( int domain,
int type,
int protocol);
domain(套接字域)取值:
AF_UNIX:unix文件系统套接字
AF_INET:因特网套接字
type(套接字类型)取值:
SOCK_STREAM:TCP流套接字
SOCK_DGRAM:UDP数据报套接字
protocol取值:
0(默认协议)
②sockaddr_in/sockaddr_un:套接字初始化
-------------------------------------------------------------------------------------
#include <sys/un.h>
struct sockaddr_un {
sa_family_t sun_family; /*AF_UNIX*/
char sun_path[]; /*pathname*/
}
---------------------------------
#include <netinet/in.h>
struct sockaddr_in {
short int sin_family; /*AF_INET*/
unsigned short int sin_port; /*Port number*/
struct in_addr sin_addr; /*Internet address*/
}
其中IP地址结构in_addr被定义为:
struct in_addr {
unsigned long int s_addr;
};
③bind:命名套接字
-------------------------------------------------------------------------------------
#include <sys/socket.h>
int bind( int socket,
const struct sockaddr *address,
size_t address_len);
④listen:服务器创建套接字队列
-------------------------------------------------------------------------------------
#include <sys/socket.h>
int listen(int socket, int backlog)
backlog表示队列长度,队列中未处理连接数大于backlog值时,拒绝连接
listen函数成功时返回0,失败时返回-1
⑤accept:服务器接受连接
-------------------------------------------------------------------------------------
#include <sys/socket.h>
int accept( int socket,
struct sockaddr *address,
size_t *address_len);
accept系统调用只有当有客户试图连接到由socket参数指定的套接字上时才返回。
accept函数将创建一个新套接字来与该客户进行通信,并返回新套接字的描述符。
当有未处理客户连接时,accept函数将返回一个新的套接字文件描述符。
当发生错误时, accept函数返回-1
若套接字队列中无未处理连接,accept将其阻塞(程序将暂停)直到有客户建立连接。
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, O_NONBLOCK|flags);
⑥connect:客户端请求连接
-------------------------------------------------------------------------------------
#include <sys/socket.h>
int connect( int socket,
const struct sockaddr *address,
size_t address_len);
将参数socket指定的套接字连接到参数address指定的服务器套接字,
address指向的结构长度有参数address_len指定。
参数socket指定的套接字必须是通过socket条用获得的一个有效的文件描述符。
connect成功时返回0,失败时返回-1。
如果连接不能立刻建立,connect调用将阻塞一段不确定的超时时间。
一旦这个超时时间到达,连接将被放弃,connect调用失败。
但如果connect调用被一个信号中断,blah, blah——
⑦close:关闭套接字
-------------------------------------------------------------------------------------
调用close函数终止服务器与客户端上套接字的连接,就如同底层文件描述符进行关闭一样。
连接的两端都关闭套接字。对服务器来说read调用返回0时关闭套接字。
但如果套接字是一个面向连接类型的,并设置了SOCK_LINGER选项,
close调用会在该套接字还有为传输数据时阻塞。
⑧主机字节序与网络字节序
-------------------------------------------------------------------------------------
例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
big-endian little-endian
0x0000 0x12 0xcd
0x0001 0x23 0xab
0x0002 0xab 0x34
0x0003 0xcd 0x12
x86系列CPU都是little-endian的字节序.
网络字节顺序是TCP/IP中规定好的一种数据表示格式,
它与具体的CPU类型、操作系统等无关,
从而可以保证数据在不同主机之间传输时能够被正确解释。
网络字节顺序采用big endian排序方式。
#include <netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short ing ntohs(unsigned short int ntohs);
htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long 类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long 类型从网络序转换到主机序
在使用little endian的系统中 这些函数会把字节序进行转换
在使用big endian类型的系统中 这些函数会定义成空宏
参考文献:
1.《linux程序设计》第4版第15章
2.http://www.cnblogs.com/jacktu/archive/2008/11/24/1339789.html