Socket网络编程
一、什么是Socket
Socket(套接字)是BSD提供的网络应用编程界面(API),Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。现在它已经是网络编程中的标准。
Socket是一种特殊的进程间通信方式,不同机器上的进程都可以使用这种方式进行通信,网络中的数据传输是一种I/O操作。Socket也是一种文件描述符,它代表了一个通信管道的一个端点。read,write,close操作可应用于Socket描述符。在socket类型的文件描述符上,可以完成建立连接,数据传输等操作。常用的Socket类型有两种:
流式Socket-SOCK_STREAM,提供面向连接的Socket
数据报式Socket-SOCK_DGRAM,提供面向无连接的Socket
二、设置IP地址和端口号
字节序转换,字节序是指一个字节在存储器中是按高字节在前还是按低字节在前存放,分为大端格式和小端格式,异构计算机之间通信,需要转换自己的字节序为网络字节序。
字节序转换函数: (包含头文件:)
uint32_t htonl() uint16_t htons()
以上返回网络字节序
uint32_t ntohl() uint16_t ntohs()
以上返回主机字节序
以下函数包含头文件
通用套接口地址结构体
struct sockaddr
{
sa_family_t
sa_family;//地址族(无符号的短整数在linux中是两个字节)
char
sa_data[14];
//地址数据
}
在使用其他套接口地址时要强制转换成通用套接口地址 (struct sockaddr
*)&servAddr
IPv4套接字地址结构体
struct
sockaddr_in
{
sa_family_t sin_family; 协议类型
in_port_t sin_port; 端口号
struct
in_addr sin_addr; IP地址
unsigned char zero[8]; 为0
};
Ip地址结构体:
struct
in_addr
{
in_addr_t s_addr;
};
struct
in_addr以一个32位无符号数来表示,通常需要用到点分十进制数串与它之间的转换,使用inet_pton和inet_ntop来处理网络字节和主机字节之间的转换,原型如下:
int inet_pton(int
family, const char *strptr,
void
*addrptr);
如果使用IPv4协议,第一个参数是AF_INET
第二个参数strprt为指向字符型的地址(ddd.ddd.ddd.ddd格式),函数将该地址转换为in_addr的结构体,并复制在*addrptr中。成功返回1,否则返回0。
const char *inet_ntop(int
family, const void
*addrptr, char *strptr,
size_t len);
这个函数作用和上面相反,多了一个参数len,它是所指向缓存区addrptr的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针。
有一个宏定义,指定了IP地址的长度为16,可以直接拿来用
#define INET_ADDRSTRLEN
16
以下函数包含头文件
三、建立Socket
创建套接字是进行任何网络通信时必须做的第一步,创建一个用于网络通信的I/O描述符(套接字),相当于在对文件读写前先用open获取文件描述符。
为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。Socket函数原型为:
int socket(int family, int type, int protocol);
family:协议族
常用的是AF_INET,代表的是IPv4协议,AF_INET6是IPv6协议
type:套接口类型
SOCK_STREAM SOCK_DGRAM
protocol:协议类别,一般为0就可以了。
调用socket函数返回一个int型的socket描述符。Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。Socket执行体为你管理描述符表。
四、做为服务器
做为服务器需要具备三个条件:
1.具备一个可以确知的地址,以便别人能找到我
2.让操作系统知道你是一个服务器,而不是一个客户端
3.等待连接的到来
1.使用一个确知的端口来接收客户端的连接,需要使用bind函数将一个地址绑定到套接字,bind函数原型如下:
int
bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
sockfd:套接口描述字
myaddr:指向特定于协议的地址结构体指针
addrlen: 该地址结构的长度
返回值:0,成功;其他,失败
2.让套接字成为被动的,使用listen函数可以将套接口由主动修改为被动,listen函数原型如下:
int listen(int
sockfd, int
backlog);
sockfd: socket套接口描述字
backlog:连接队列的长度
返回值:0,成功;其他,失败
3.等待连接的到来,使用accept函数从连接队列中取出一个已经建立的连接,如果没有任何连接可用,则进入睡眠等待(这个函数是阻塞的)。函数原型如下:
int accept(int
sockfd, struct sockaddr *cliaddr,
socklen_t *addrlen);
sockfd:
socket套接口描述字 cliaddr: 客户端地址
addrlen:客户端地址结构体长度
返回值:已连接的套接口(代表当前连接)
五、做为客户端
客户端要知道服务哭的IP地址以及端口号,需要主动跟服务器建立连接,对于TCP协议,连接建立后才可以开始传输数据,使用connect函数建立连接,原型如下:
int connect(int sockfd, const
struct sockaddr *addr, socklen_t
len);
addr:
服务器地址 addrlen:服务器地址结构体长度
返回值:0,成功;其他,错误。Connect函数建立连接后不会产生新的套接口
六、传输数据
当连接建立后,通信的两端便具备两个套接口,可以用read,write函数从这个通信管道读取后写入数据.
Send()和recv()这两个函数用于面向连接的socket上进行数据传输。
Send()函数原型为:
int send(int
sockfd, const void
*msg, int
len, int
flags);
Sockfd是你想用来传输数据的socket描述符;msg是一个指向要发送数据的指针;Len是以字节为单位的数据的长度;flags一般情况下置为0(关于该参数的用法可参照man手册)。
Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。在程序中应该将send()的返回值与欲发送的字节数进行比较。当send()返回值与len不匹配时,应该对这种情况进行处理。
char *msg = "Hello!";
int len, bytes_sent;
……
len = strlen(msg);
bytes_sent = send(sockfd, msg,len,0);
……
recv()函数原型为:
int recv(int sockfd,
void *buf,
int
len, unsigned
int flags);
Sockfd是接受数据的socket描述符;buf
是存放接收数据的缓冲区;len是缓冲的长度。Flags也被置为0。Recv()返回实际上接收的字节数,当出现错误时,返回-1并置相应的errno值。
使用close函数关闭套接字,关闭一个代表已建立连接的套接字将导致另一端接收到一个0长度的数据包。服务器关闭socket创建的套接字导致服务器无法继续接受新的连接,蛤不会影响已经建立的连接。关闭accept返回的套接字将导致它所代表的连接被关闭,但不会影响服务器的监听。客户端用close,就是关闭连接。
你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而一个方向上的数据传输继续进行。如你可以关闭某socket的写操作而允许继续在该socket上接受数据,直至读入所有数据。
int
shutdown(int sockfd,
int how);
Sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式:
·0-------不允许继续接收数据
·1-------不允许继续发送数据
·2-------不允许继续发送和接收数据,
·均为允许则调用close ()
shutdown在操作成功时返回0,在出现错误时返回-1并置相应errno。
例子:
#include
#include
#include
// bzero
#include
#include
#include
#include
// inet_ntop
//=============================================================
//
语法格式: void
main(void)
//
实现功能: 主函数,建立一个TCP Echo
Server
//
入口参数: 无
//
出口参数: 无
//=============================================================
int main(int argc, char *argv[])
{
char recvbuf[2048];
//
接收缓冲区
int sockfd;
//
套接字
struct sockaddr_in servAddr;
//
服务器地址结构体
unsigned short port = 8000;
//
监听端口
if(argc > 1)
//
由参数接收端口
{
port = atoi(argv[1]);
}
printf("TCP Server Started at port %d!\n", port);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//
创建TCP套接字
if(sockfd < 0)
{
perror("Invalid socket");
exit(1);
}
bzero(&servAddr, sizeof(servAddr));
//
初始化服务器地址
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Binding server to port %d\n", port);
if(bind(sockfd, (struct sockaddr*)&servAddr,
sizeof(struct sockaddr)) != 0)
{
close(sockfd);
perror("binding err!");
exit(1);
}
if(listen(sockfd, 1) != 0)
{
close(sockfd);
perror("listen err!");
exit(1);
}
printf("waiting client...\n");
while(1)
{
char cliIP[INET_ADDRSTRLEN];
//
用于保存客户端IP地址
size_t recvLen;
struct sockaddr_in cliAddr;
//
用于保存客户端地址
size_t cliAddrLen = sizeof(cliAddr);
//
必须初始化!!!
int connfd = accept(sockfd, (struct
sockaddr*)&cliAddr,
&cliAddrLen);
//
获得一个已经建立的连接
if(connfd < 0)
{
close(sockfd);
perror("accept err!");
exit(1);
}
inet_ntop(AF_INET, &cliAddr.sin_addr.s_addr, cliIP,
INET_ADDRSTRLEN);
printf("client ip = %s\n", cliIP);
while((recvLen = read(connfd, recvbuf, 2048)) >
0)
{
write(connfd, recvbuf, recvLen);
}
close(connfd);
printf("client closed!\n");
}
close(sockfd);
return 0;
}
分析:
服务器:
unsigned short port = 8000;
定义端口号为8000
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM,
0);
socket函数创建一个套接字,使用IPv4,TCP协议
要加上一个错误判断,如果socket返回值小于0,就是错误的
struct sockaddr_in servAddr;
bzero(&servAddr,
sizeof(servAddr));
定义了服务器地址结构体,并初始化,bzero相当于memset,将结构体内容清0
给服务器地址赋值:
servAddr.sin_family = AF_INET;
//IPv4
servAddr.sin_port = htons(port);
//端口号,注意要把port转换为(16位)网络字节序
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//IP地址,用INADDR_ANY指定为任意IP,转换成(32位)网络字节序
bind(sockfd, (struct
sockaddr*)&servAddr, sizeof(struct
sockaddr))
绑定地址,要把服务器地址强制转换成sockaddr的结构体,同样加错误判断
listen(sockfd, 1)
开始监听,队列大小为1,只允许一个客户端访问,但实际在linux下不起作用
客户端:
char cliIP[INET_ADDRSTRLEN];
定义一个存放客户端IP地址的数组,大小为16
struct sockaddr_in cliAddr;
定义了客户端地址结构体
int connfd
connfd = accept(sockfd, (struct
sockaddr*)&cliAddr,
&cliAddrLen);
客户端连接到服务器,获得一个已经建立的连接connfd,这个就是当前连接,对它进行读写操作
inet_ntop(AF_INET,
&cliAddr.sin_addr.s_addr, cliIP,
INET_ADDRSTRLEN);
将客户端的IP地址转换成字符串,存放在cliIP中,INET_ADDSTRLEN指定大小为16
到这为止,连接已经建立完成
=======================================
笔记
网络的一些相关知识:
网卡功能: 载波侦听, 冲突检测, 随机延时等待;
网线一般不得超过100米;
交换机的功能: 动态建立连接桥梁, 探知端口上有几台电脑, 自学习;
远距离传送: 铜线 + 中继器/光纤/微波 等 挑战在于:如何传更远, 更快, 减少错误;
局域网物理层的功能目标: 更准, 更快, 如何避免冲突;
链路, 就是连接相邻两台电脑的线路; 如何可靠的传输, 通过校验, 不是绝对安全, 但已经足够;
protocol是用来定义数据桢格式, 交互顺序的. 比如以太网802.1, 广域网ppp
? 流控制, 应答, "滑动窗口协议"
点到点保证可靠传送, 端到端可靠吗? 由于当中如果缺少整桢数据, 端到端并不可靠.
路由协议是用于路由器之间维护路由表的协议:
每个路由的下一跳要明确; 定期广播; 启动时广播;
以太网是当前应用最普遍的局域网技术;
mac地址在局域网内不重复, 但在不同的局域网可能重复;
socket = Sip + Sport +Tip +Tport 唯一确定一条网络通路;
HTTP请求格式:
telnet 80
GET / HTTP/1.1 \n
HOST: \n\n
如何软件手段获取域名的IP地址? 如何提取网页的特定信息?
linux中看路由: traceroute + webname
xp中看路由: tracert + webname
TCP/IP协议族层次,由上往下: 应用层->传输层->网络层->链路层
OSI参考模型7层, 由上往下: 应用层, 表示层, 会话层->传输层->网络层->数据链路层, 物理层
应用层协议:
FTP file transfer protocol, 允许用户以文件操作的方式与另一主机通信;
SMTP simple mail transfer protocol, 为系统间传送电子邮件;
TELNET telnet terminal protocol, 允许用户以虚终端方式访问远程主机;
HTTP hypertext transfer protocol, 环球www的基础;
TFTP trivial file transfer protocol, ftp的简化版本, 基于UDP协议;
传输层协议:
TCP transmission control protocol, 一种提供给用户进程的可靠的全双工的字节流面向连接的协议.
UDP user datagram protocol, 一种提供给用户进程的无连接的协议, 不执行正确性检查.
网络层协议:
IP internet protocol, 负责主机间数据路由和网络上数据的存储, 同时为ICMP, TCP, UDP提供分组发送服务;
ARP address resolution protocol, 此协议将网络地址映射到硬件地址;
RARP reverse address resolution protocol, 此协议将硬件地址映射到网络地址;
ICMP internet control message protocol, 此协议处理信关和主机间的差错和传送控制; 本身也是IP的一部分;
IP地址, 32bit, 4字节, 通常采用点分十进制记法: 192.168.0.1 ; Dotted decimal string representation;
特殊的IP地址: 255.255.255.255 网络内广播,路由器不转发;
子网掩码, 表明了该IP所在网络的地址范围;
路由表, 路由, 路由节点, 接口, 条目, 缺省路由条目;
路由: 数据报从源地址到目的地址所经过的道路, 由一系列路由节点的地址构成.
小端存储, 0x01020304, 后面的是小地址;
大端存储, 0x01020304, 前面的是小地址; 网络数据就是大端格式;
i386是小端存储, 一些大端存储的CPU有POWER PC, SUNSPARC.
转换函数:
uint16_t htons(uint16_t value); //s代表short
uint32_t htonl(uint32_t value); //l代表long
返回网络顺序的值;
uint16_t ntohs(uint16_t value);
uint32_t ntohs(uint32_t value);
返回主机顺序的值;
其他常用函数:
void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *dest, size_t nbytes);
void bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
void *memset(void *dest, int c, size_t len);
void *memcpy(void *dest, const void *src, size_t nbytes);
int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);
地址转换:
点分十进制字符串 --inet_aton -->网络顺序32位整形值
162.105.129.7 presentation n->numeric
#include
int inet_pton( int family, const char *strptr, void *addrptr); 有效地址返回1, 无效返回0, 出错返回-1;
const char *inet_ntop( int family, const void *addrptr, char *strptr, size_t len);
成功返回结果指针, 出错返回NULL;
family 可以是AF_INET, AF_INET6
len 的定义如下:
#include
#define INET_ADDRSTRLEN 16 /*for ipv4 dotted-decimal */
#define INET6_ADDRSTRLEN 46 /*for ipv6 hex string */
socket是编程接口, 是一系列函数调用; 一对socket构成了交流数据的一个通道; 一个进程可以有多个socket;
#include
#include
int socket (int domain, int type, int protocol); //成功返回一个非负的描述符, 出错返回-1;
domain description
AF_INET Ipv4 protocols
AF_INET6 Ipv6 protocols
AF_UNIX Unix domain protocols
AF_UNSPEC Unspecified
type description
SOCK_STREAM stream socket
SOCK_DGRAM datagram socket
SOCK_RAW raw socket
protocol: 0
#include
#include
int bind( int sockfd, struct sockaddr *my_addr, socklen_t addlen); //成功返回0, 出错返回-1;
struct sockaddr{
sa_family_t sa_family;
char sa_data[14];
}
struct sockaddr_in{
sa_family_t sin_family;
in_port_t sin_port; //2bytes
struct in_addr sin_addr; //4bytes
char sin_zero[8];
}
这两个结构体指针可以互相强制转换;
地址值可以是INADDR_ANY通配地址, 也可以是本地ip地址.
本地可以有多个IP地址, 一旦绑定, 此socket上发送的数据以此地址为IP源地址;
端口可以分配一个非0, 也可以是0, 此时系统会分配一个非0值;
客户端通常不指定本地IP, 系统根据目的地址选择要使用的网卡, 然后用该网卡的地址作为源地址;
服务器, 一般设为INADDR_ANY, 由系统挑选一地址, 该地址是客户端连接请求是确定的;
客户端通常不需要bind, 服务器需要bind以表明使用的端口;
#include
int listen( int sockfd, int backlog); //成功返回0, 出错返回-1;
该函数使socket在协议地址上监听, 并为该socket建立一个连接队列, 保存到达的服务请求, 直到程序处理;
backlog 指定在请求队列中允许的最大请求数, 进入的连接请求将在队列中等待被accept. 多数系统缺省20;
如果队列已满, 新来的请求将被拒绝, 客户收到一个出错信息;
#include
#include
int accept( int sockfd, struct sockaddr *addr, socklen_t *addrlen); //成功返回非负的连接描述符, 出错-1;
用listen建立好输入队列后, 服务器可以调用accept阻塞式的等待客户的连接请求;
连接成功后往返回的连接描述符来读写数据; sockfd继续用于监听连接请求;
addr 用来存放客户端主机的信息;
#include
#include
int connect( int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen); //成功返回0, 出错-1;
用于客户端向服务器发出连接请求, 成功后可以用sockfd来读写数据;
serv_addr 是包含远端主机IP地址和端口号的指针;
出错返回-1, 并设置errno, 常见如下:
ETIMEOUT 连接超时;
ECONNREFUSED 服务器不在listen;
ENETUNREACH 网络不通
常用于TCP客户端, 服务器一般不主动去连;
在UDP应用中, 也可以用connect, 目的是建立双方的ip-port对, 可直接使用read, write, 无需在sendto中指定;
#include
int read( socketfd, void *buf, size_t n); //成功返回读取的字节数, 出错返回-1;
int write(socketfd, void *buf, size_t n); //成功返回写入的字节数, 出错返回-1;
对于read, 如果读出的数目小于n, 可能是接近文件结尾, 从终端读, 被信号中断等原因;
如果还没开始读, 就被信号打断, 此时返回-1, 并置errno为EINTR.
对于write, 如果还没开始写, 就被信号打断, 此时返回-1, 并置errno为EINTR.
#include
#include
flags
description
recv
send
MSG_DONTROUTE
bypass routing table lookup
*
MSG_DONTWAIT
only this operation is nonblocking
*
*
MSG_OOB
send or receive out-of-band data
*
*
MSG_PEEK
peek at incoming message
*
MSG_WAITALL
wait for all the data
*
#include
int close( int fd); //成功返回0, 出错返回-1;
用于TCP时, 如果发送队列非空, 发送之, 然后终止TCP连接;
#include
#include
int recvfrom( int sockfd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
int sendto( int sockfd, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
这两个函数比recv, send这两个函数多了后2个地址参数;包含了IP地址和端口信息; 都可以用在TCP, UDP情况;
from是等待被填写的消息的源地址及端口, to是填好的目的地址及端口;
可设置socket为非阻塞型:
#include
#include
int fcntl( int fd, int cmd);
int save_flags;
save_flags = fcntl(socket_fd, F_GETFL); //获得当前状态
save_flags | = O_NONBLOCK;
fcntl( socket_fd, F_SETFL, save_flags); //设置指定的新状态
设置为非阻塞后:
对于read, recv, recvfrom 如果没有可用的信息, 返回-1, errno设为EAGAIN;
对于write, send, sendto 如果消息无法放入buffer, 返回-1, errno设为EAGAIN;
对于accept 如果不行, 返回-1, errno设为EAGAIN;
对于connect, 如果不行, 返回-1, errno设为EINPROGRESS;
select及其相关函数:
//according to POSIX 1003.1-2001.
#include
//according to earlier standards.
#include
#include
#include
int select(int maxfdpl, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
成功返回所有sets中描述符的个数, 超时返回0, 出错返回-1;
检查readfds中带1的位, 若有数据可读, 1保留, 否则清零;
检查writefds中带1的位, 若写不被阻塞, 表示可写, 1保留, 否则清零;
最后返回剩下的累计readfds, writefds, exceptfds当中1的总数;
四个宏用于fd_set操作:
FD_CLR(int fd, fd_set *set); //用来对set删除fd;
FD_ISSET(int fd, fd_set *set); //指示fd是不是已经是set的一部分;
FD_SET(int fd, fd_set *set); //对set添加fd;
FD_ZERO(fd_set *set); //清空set;
timeout是从调用开始到select返回前, 会经历的最大等待时间;
如果为0, 会立即返回; 如果为NULL, 会阻塞式等待;
在linux中, select函数会改变timeout值, 指示还剩下的时间, 所以, 最好在循环里要重新给timeout赋值;
struct timeval{
long tv_sec; //seconds
long tv_usec; //microseconds
}
#include
signal(SIGPIPE, SIG_IGN) 忽略SIGPIPE信号, 此处没用sigaction函数;
如果服务端已经关闭, client继续给这个连接发送内容, 第一次写, 根据TCP协议, 会收到RST响应, 如果还要写, 系统会发送个SIGPIPE信号给进程, 该信号的默认反应是关闭进程; 在此忽略.
如果用^C把server终止掉, 由于client端没有执行close来关闭连接, 连接还会等待client的FIN包一段时间,
如果用netstat -a查看, 发现有FIN_WAIT2状态存在, 这说明目前有socket在此地址上使用, 再次bind失败.
解决办法是: 使用setsockopt, 使这个socket可以被重用地址, 在soket调用和bind之间加上这一段:
int opt=1;
setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
#define offset( TYPE, MEMBER ) ( ( int ) &( ( TYPE * ) 0 ) ->MEMBER)
该宏用来获取结构体成员的偏移量;
服务端bind不是必须的, 它是要告诉操作系统, 某个socket使用某个地址和端口, 如果不指定, 系统会分配一个.
UDP客户端也能使用connect, 然后也可以使用无地址信息的读写函数了, 如:read, write, send, recv等.
服务端的程序可以有几种方案: 多进程, 多线程, select,
总而言之:
对于server, 步骤如下:
配置本地要监听的sin地址->socket得到listen_fd->
把listen_fd监听描述符bind到sin上->设置listen开始监听->
acept阻塞等待, 得到conn_fd用于读写, 得到pin的被填充的内容保存客户端信息->
对conn_fd进行read, write操作->与某客户端连接结束后close(conn_fd)->
整个服务程序结束时close(listen_fd);
对于client, 步骤如下:
配置目标地址pin->socket得到sock_fd->
用sock_fd去connect目标地址pin, 若成功返回则可开始用sock_fd进行read, write操作->
结束后close(sock_fd);
一些关于socket的例程:
//判断大小端的方法:
uion{
int s;
char c[4];
}un;
un.s = 0x01020304
if (un.c[0] == 1)
printf("big-endian\n");
if (un.c[0] == 4)
printf("little-endian\n");
else
printf("unknow\n");
/*client.c
*a simple client program
*/
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 80
int port = 8000;
int main(int argc, char *argv[])
{
struct sockaddr_in pin;
char buf[MAXLINE];
int sock_fd;
char *str = "A default test string";
if (argc > 1)
str = argv[1];
bzero(&pin, sizeof(pin));
pin.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &pin.sin_addr);
pin.sin_port = htons(port);
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
connect(sock_fd, (void*)&pin, sizeof(pin));
write(sock_fd, str, strlen(str) + 1);
read(sock_fd, buf, MAXLINE);
printf("Response from server:%s\n", buf);
close(sock_fd);
return 0;
}
/*server.c
*a simple server program
*/
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 80
int port = 8000;
int main(void)
{
struct sockaddr_in sin;
struct sockaddr_in pin;
int listen_fd;
int conn_fd;
int address_size = sizeof(pin);
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i;
int len;
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin));
listen(listen_fd, 20);
printf("Accepting connections ...\n");
while(1)
{
conn_fd = accept(listen_fd,
(struct sockaddr *)&pin, &address_size);
read(conn_fd, buf, MAXLINE);
printf("received from client %s at port %d: %s\n",
inet_ntop(AF_INET, &pin.sin_addr, str,
sizeof(str)), ntohs(pin.sin_port), buf);
//just convert the characters to upper case
len = strlen(buf);
for (i=0; i/*client.c
*socket client with error detect
* and sockopt
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 80
int port = 8000;
int main(int argc, char *argv[])
{
struct sockaddr_in pin;
char buf[MAXLINE];
int sock_fd;
char str[MAXLINE];
char *myip = "127.0.0.1";
int n;
if (argc > 1)
{
myip = argv[1];
}
bzero(&pin, sizeof(pin));
pin.sin_family = AF_INET;
inet_pton(AF_INET, myip, &pin.sin_addr);
pin.sin_port = htons(port);
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd == -1)
{
perror("call to socket");
exit(1);
}
n = connect(sock_fd, (void*)&pin, sizeof(pin));
if (n == -1)
{
perror("call to connect");
exit(1);
}
while (fgets(str, MAXLINE, stdin) != NULL)
{
writeagain:
n = write(sock_fd, str, strlen(str) + 1);
if (n == -1)
{
if (errno == EINTR)
goto writeagain;
else
{
printf("call to write");
exit(1);
}
}
readagain:
n = read(sock_fd, buf, MAXLINE);
if (n == -1)
{
if (errno == EINTR)
goto readagain;
else
{
perror("call to read");
exit(1);
}
}else if (n == 0)
{
printf ("the other side has been closed.\n");
close(sock_fd);
}
printf("Response from server:%s\n", buf);
/*
if (n == 0)
printf("the other side has been closed.\n");
else
printf("Response from server:%s\n", buf);
*/
if (strncmp(str, "bye", 3) == 0)
break;
}
sleep(1);
n = close(sock_fd);
if (n == -1)
{
perror("call to close");
exit(1);
}
return 0;
}
/**
#########################################################
# Filename: server.c
# Description: select server
#########################################################
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 80
int port = 8000;
int main (void)
{
struct sockaddr_in sin;
struct sockaddr_in pin;
int listen_fd;
int conn_fd;
int sock_fd;
int nready;
int client[FD_SETSIZE];
int maxi;
int maxfd;
fd_set rset;
fd_set allset;
int address_size;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN]; // 16
int i;
int len;
int n;
bzero (&sin, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons (port);
listen_fd = socket (AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1)
{
perror ("call to socket");
exit (1);
}
{
int opt = 1;
setsockopt (listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
}
n = bind (listen_fd, (struct sockaddr *) &sin, sizeof (sin));
if (n == -1)
{
perror ("call to bind");
exit (1);
}
n = listen (listen_fd, 20);
if (n == -1)
{
perror ("call to listen");
exit (1);
}
printf ("Accepting connections...\n");
maxfd = listen_fd;
maxi = -1;
for (i = 0; i maxfd)
maxfd = conn_fd;
if (i > maxi)
maxi = i;
if (--nready /*udpclient.c*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 80
int port = 8000;
int main(int argc, char *argv[])
{
struct sockaddr_in pin;
struct sockaddr_in rin;
char buf[MAXLINE];
int sock_fd;
char str[MAXLINE];
char sip[INET_ADDRSTRLEN];
int n;
int address_size;
bzero(&pin, sizeof(pin));
pin.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &pin.sin_addr);
pin.sin_port = htons(port);
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd == -1)
{
perror("call to socket");
exit(1);
}
while (fgets(str, MAXLINE, stdin) != NULL)
{
sendto(sock_fd, str, strlen(str) + 1, 0,
(struct sockaddr *)&pin, sizeof(pin));
if (n == -1)
{
perror("call to sendto.\n");
exit(1);
}
address_size = sizeof(rin);
n = recvfrom(sock_fd, buf, MAXLINE, 0, (struct sockaddr*)
&rin, &address_size);
if (n == -1)
{
perror("call to recvfrom.\n");
exit(1);
}else
{
printf("Response from %s port %d: %s\n",
inet_ntop(AF_INET, &rin.sin_addr, sip,
sizeof(sip)), ntohs(rin.sin_port),buf);
}
}
close(sock_fd);
if (n == -1)
{
perror("call to close. \n");
exit(1);
}
return 0;
}
/*udpserver.c*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 80
int port =8000 ;
int main(void)
{
struct sockaddr_in sin;
struct sockaddr_in rin;
int sock_fd;
int address_size;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i;
int n;
int len;
bzero(&sin,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=INADDR_ANY;
sin.sin_port =htons(port);
sock_fd= socket(AF_INET,SOCK_DGRAM,0);
if(sock_fd== -1){
perror("call to socket");
exit(1);
}
n=bind(sock_fd,(struct sockaddr *) &sin,sizeof(sin));
if(n == -1){
perror("call to bind");
exit(1);
}
while(1)
{
address_size=sizeof(rin);
n =recvfrom(sock_fd,buf,MAXLINE,0,(struct sockaddr *) &rin,
&address_size);
if( n == -1){
perror("call to recvfrom.\n");
exit(1);
}
printf("received from client %s at port %d: %s\n",
inet_ntop(AF_INET , &rin.sin_addr,str,
sizeof(str)),ntohs(rin.sin_port),buf);
//just convert the characters to upper case
len =strlen(buf);
for (i=0; i/*unblkserver.c
*unblock socket server*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 80
int port = 8000;
int main(void)
{
struct sockaddr_in sin;
struct sockaddr_in rin;
int sock_fd;
int address_size;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i;
int n;
int len;
long flags;
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd == -1)
{
perror("call to bind");
exit(1);
}
n = bind(sock_fd, (struct sockaddr *)&sin, sizeof(sin));
if (n == -1)
{
perror("call to bind");
exit(1);
}
flags = fcntl(sock_fd, F_GETFL);
flags |= O_NONBLOCK;
if (fcntl(sock_fd, F_SETFL, flags) == -1)
{
perror("trying to set sock_fd to non-blocking");
exit(1);
}
printf("sock_fd has been set to non-blocking mode.\n");
while (1)
{
sleep(3);
address_size = sizeof(rin);
n = recvfrom(sock_fd, buf, MAXLINE, 0, (struct sockaddr*)
&rin, &address_size);
if (n == -1 && errno != EAGAIN)
{
perror("call to recvfrom");
exit(1);
}else if (n == 0 || (n == -1 && errno == EAGAIN))
{
printf("no data yet\n");
continue;
}else
{
printf("received from client %s at port %d: %s\n",
inet_ntop(AF_INET, &rin.sin_addr, str,
sizeof(str)), ntohs(rin.sin_port), buf);
}
//just convert
len = strlen(buf);
for (i = 0; i
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 1024
int port = 80;
int main(int argc, char *argv[])
{
FILE *fp;
int sock_fd, ret;
struct sockaddr_in pin;
char buf[MAXLINE + 1];
char *str = "GET / HTTP/1.1\n HOST:\n\n";
char *myip = "202.108.9.31"; //
if (argc > 1)
{
myip = argv[1];
}
if ((fp = fopen("163.html", "w+")) == NULL)
{
printf("Cannot open 163.html");
exit(1);
}
bzero(&pin, sizeof(pin));
pin.sin_family = AF_INET;
inet_pton(AF_INET, myip, &pin.sin_addr);
pin.sin_port = htons(port);
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock_fd == -1)
{
perror("call to socket");
exit(1);
}
ret = connect(sock_fd, (void*)&pin, sizeof(pin));
if (ret == -1)
{
perror("call to connect");
goto PROGRAM_EXIT;
}
WRITE_AGAIN:
ret = write(sock_fd, str, strlen(str));
if (ret == -1)
{
if (errno == EINTR)
goto WRITE_AGAIN;
else
{
printf("call to write");
goto PROGRAM_EXIT;
}
}
/* read data from server */
while(1)
{
READ_AGAIN:
ret = read(sock_fd, buf, MAXLINE);
if (ret > 0)
{
buf[ret] = '\0';
printf("Response from server:%s\n", buf);
fprintf(fp, "%s", buf);
}
else if (ret == -1)
{
if (errno == EINTR)
goto READ_AGAIN;
else
{
perror("call to read");
goto PROGRAM_EXIT;
}
}
else if (ret == 0)
{
printf ("the other side has been closed.\n");
break;
}
}
PROGRAM_EXIT:
close(sock_fd);
fclose(fp);
return 0;
}
/*domainsoc.c
*UNIX Domain Socket IPC
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd, size;
struct sockaddr_un un;
un.sun_family = AF_UNIX;
strcpy(un.sun_path, "foo.socket");
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) serv_accept
*/
#include
#include
#include
#include
#include
#include
#define STALE 30
#define QLEN 10
int serv_accept(int listenfd, uid_t *uidptr)
{
int clifd, len, err, rval;
time_t staletime;
struct sockaddr_un un;
struct stat statbuf;
len = sizeof(un);
if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) serv_listen
*/
#include
#include
#include
#include
#define QLEN 10
int serv_listen(const char *name)
{
int fd, len, err, rval;
struct sockaddr_un un;
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) cli_conn
*/
#include
#include
#include
#include
#include
#include
#define CLI_PATH "/var/tmp/"
/* +5 for pid =14 char */
#define CLI_PERM S_IRWXU
/* rwx for user only */
/*
* Creat a client endpoint and connect to a server .
* Return fd if all OK ,信息点滴:
端口号信息可以查看/etc/services.
/etc/resolv.conf 域名服务器设置;
/etc/hosts ? 过滤网站
ps aux | less
netstat -a | grep :80
rpm -ivh --nodeps -force name.rpm
/usr/share/applications 应用程序菜单所在
slash->/ period->. comma->,
^ +. 切换全角半角中文