本章讲解编写一个完整的TCP客户/服务器程序所需要的基本套接字函数。

socket函数

#include <sys/socket.h>
int socket(int family,int type,int protocol);
//返回:成功则为非负描述符,若出错则为-1

family参数指明协议族,它是如下某个常值

type参数指明套接字类型,它是如下某个常值

protocol参数为下面某个协议类型常值,或者设为0,以选择所给定family和type组合的系统默认值

下图展示了基本TCP客户/服务器程序的套接字函数

connect函数

TCP客户用connect函数来建立与TCP服务器的连接

#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr *servaddr,socklen_t addrlen)
//返回:若成功则为0,若出错则为-1

sockfd是由socket函数返回的套接字描述符,第二个、第三个参数分别是一个指向套接字地址结构的指针和该结构的大小。

bind函数

bind函数把本地协议地址赋予一个套接字

#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);
//返回:若成功则为0,若出错则为-1

listen函数

listen函数仅由TCP服务器调用,它做两件事情。

1.当socket函数创建一个套接字时,它被假设为一个主动套接字(将调用connect发起连接的客户端套接字)

listen函数把未连接的套接字转换成一个被动套接字,指示内核应接受该套接字的连接请求。

2.本函数的第二个参数规定了内核应该为相应套接字排队的最大连接个数。

#include <sys/socket.h>
int listen(int sockfd,int backlog);
//返回:若成功则为0,若出错则为-1

本函数通常应该在调用socket和bind这两个函数之后,并在调用accept函数之前调用。

accept函数

accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠。

#include <sys/socket.h>
int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);
//返回:若成功则为非负描述符,若出错则为-1

参数cliaddr和addrlen用来返回已连接的对端进程(客户)的协议地址。

如果accept成功,那么其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP连接。

在讨论accept函数时,我们称它的第一个参数为监听套接字(由socket创建,随后用作bind和listen的第一个参数的描述符),称它的返回值为已连接套接字描述符。

下面程序演示了上面全部函数的用法,这个服务器是一个迭代服务器。是一个显示客户IP地址和端口号的时间获取服务器程序。

 #include    "unp.h"
#include <time.h> int
main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t len;
struct sockaddr_in servaddr, cliaddr;
char buff[MAXLINE];
time_t ticks; listenfd = Socket(AF_INET, SOCK_STREAM, ); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(); /* daytime server */ Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); for ( ; ; ) {
len = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &len);
printf("connection from %s, port %d\n",
Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)),
ntohs(cliaddr.sin_port)); ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
Write(connfd, buff, strlen(buff)); Close(connfd);
}
}

fork和exec函数

fork函数是UNIX中派生新进程的唯一方法

#include <unistd.h>
pid_t fork(void);
//返回:在子进程中为0,在父进程中为子进程ID,若出错则为-1

存放在硬盘上的可执行程序文件能够被UNIX执行的唯一方法是现有调用6个exec函数的某一个

#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
int fexecve(int fd,char *const argv[],char *const envp[]);

exec把当前进程映像替换成新的程序文件,而且该新程序通常从main函数开始执行。

关于fork和exec函数可以查看之前写的apue的文章:http://www.cnblogs.com/runnyu/p/4638913.html

并发服务器

上面有一个迭代服务器的例子,对于像时间获取这样的简单服务器来说,这就够了。

然后当服务一个客户请求可能花费较长时间时,我们并不希望整个服务器被单个客户长期占用,而是希望同时服务多个客户。

UNIX编写并发服务器程序最简单的办法就是fork一个子进程来服务每个客户,下面给出了一个典型的并发服务器程序的轮廓。

 pid_t pid;
int listenfd,connfd;
listenfd=Socket(...);
/* fill in sockaddr_in{} with server'swell-known port */
Bind(listenfd,...);
Listen(listenfd,LISTENQ);
for(;;)
{
connfd=Accept(listenfd,...); /* probably blocks */
if((pid=Fork())==)
{
Close(listenfd); /* child closes listening socket */
doit(connfd); /* process the request */
Close(connfd); /* done with this client */
exit(); /* child terminates */
}
Close(connfd) /* parent closes connected socket */
}

当一个连接建立时,accept返回,服务器接着调用fork,然后由子进程服务客户(通过已连接套接字connfd),父进程等待另一个连接(通过监听套接字listenfd)

close函数

通常的UNIX close函数也可用来关闭套接字。

#include <unistd.h>
int close(int sockfd);
//返回:若成功则为0,若出错则为-1

描述符引用计数

在上面并发服务器框架中,父进程关闭已连接套接字只是导致相应描述符的应用计数值减1。

既然引用计数值大于0,这个close调用并不引发TCP的四分组连接终止序列,知道子进程使用close关闭该套接字(引用次数为0)才终止TCP连接。

getsockname和getpeername函数

getsockname返回某个套接字关联的本地协议地址,getpeername函数返回与某个套接字关联的外地协议地址。

#include <sys/socket.h>
int getsockname(int sockfd,struct sockaddr *localaddr,socklen_t *addrlen);
int getpeername(int sockfd,struct sockaddr *peeraddr,socklen_t *addrlen);
//均返回:若成功则为0,若出错则为-1

UNP学习笔记(第四章 基本TCP套接字编程)的更多相关文章

  1. UNP学习笔记(第八章 基本UDP套接字编程)

    UDP应用程序客户不与服务器建立连接,而是只管使用sendto函数给服务器发送数据报,其中必须指定目的地的地址作为参数. 下图给出典型的UDP客户/服务器程序的函数调用. recvfrom和sendt ...

  2. unix网络编程第四章----基于TCP套接字编程

    为了执行网络I/O操作.进程必须做的第一件事情就是调用Socket函数.指定期待的通信协议 #include<sys/socket.h> int socket(int family,int ...

  3. UNP——第四章,TCP套接字编程

    1.socket 函数 首先被调用的函数,用于选择通信协议. socket调用成功后,得到的套接字为主动套接字CLOSED状态. PF 和 AF 的关系 PF的是协议族,AF是地址族,理论上一个PF包 ...

  4. 第四章 基本TCP套接字编程 第五章 TCP客户/服务器程序实例

    TCP客户与服务器进程之间发生的重大事件时间表 TCP服务器 socket() --- bind() --- listen() --- accept() --- read() --- write -- ...

  5. 【UNIX网络编程(四)】TCP套接字编程具体分析

    引言: 套接字编程事实上跟进程间通信有一定的相似性,可能也正由于此.stevens这位大神才会将套接字编程与进程间的通信都归为"网络编程",并分别写成了两本书<UNP1> ...

  6. UNP学习笔记(第十八章 路由套接字)

    路由套接字上支持3种类型的操作 1). 进程能通过写路由套接字向内核发消息. 2). 进程能通过路由套接字从内核读消息. 3). 进程可以用sysctl函数得到路由表或列出所有已配置的接口. 数据链路 ...

  7. UNIX网络编程 第4章 基本TCP套接字编程

    本章的几个函数在很大程度上展示了面向对象与面向过程的不同之处.

  8. UNP学习笔记1——基本TCP套接字编程

    1 套接字地址结构 大多数套接字函数都需要一个指向套接字地址结构的指针作为参数.每个协议族都定义了自己的套接字结构.这些套接字的结构以sockaddr_开头,以每个协议族唯一的后缀名结尾. 1.1 I ...

  9. TCP套接字编程模型及实例

    摘要:     本文讲述了TCP套接字编程模块,包括服务器端的创建套接字.绑定.监听.接受.读/写.终止连接,客户端的创建套接字.连接.读/写.终止连接.先给出实例,进而结合代码分析. PS:本文权当 ...

随机推荐

  1. 抓取js动态生成数据

    最近在抓数据,一般的网页数据抓取相对容易一些,今天在抓电视猫的节目单,发现有些数据时抓取不到的,Java端得到的HTML文件里面没有某一段代码,查了很多资料,发现说是js动态生成的数据,无法直接抓取, ...

  2. pdf生成

    要用本文的方法生成PDF文件,需要两个控件:itextsharp.dll和ICSharpCode.SharpZipLib.dll,由于示例代码实在太多,我将代码全部整理出来,放在另外一个文件“示例代码 ...

  3. 刷题总结—— Scout YYF I(poj3744 矩阵快速幂+概率dp)

    题目: Description YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate int ...

  4. java拼接字符串用StringBuilder

    StringBuilder builder = new StringBuilder(); String s1="abc"; for(int i=0;i<10000000;i+ ...

  5. mac 安装 photoshop CS6

    终于找到破解了,索性写个图文并茂的全解吧.1. 官方下载photosho CS6 machttp://trials2.stage.adobe.com/A ... hotoshop_13_LS3.dmg ...

  6. NOI2001食物链

    描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A吃B,B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人 ...

  7. query带进度上传插件Uploadify(ASP.NET版本)使用

    原文发布时间为:2010-05-13 -- 来源于本人的百度文章 [由搬家工具导入] 本文将带给大家很帅的jquery上传插件,ASP.NET版本的哦,这个插件是Uploadify实现的效果非常不错, ...

  8. js禁用"Backspace"键(即禁止网页倒退)

    项目遇到的一个问题一个普通网页,如果这个网页上没有焦点的话,那么点击"Backspace"键的时候,网页会回退(倒退到上一个网页),这样就会就有一个问题,当我在一个输入框进行输入的 ...

  9. hdu 2147 kiki's game 组合游戏 找规律

    题目链接 题意 两人轮流将硬币从\((n,m)\)移动到\((1,1)\),每次只能向下或向左或向左下移动一格,最后无法移动者输.问先手会赢还是会输. 思路 找规律 -- P N P N P N P ...

  10. [Json] 1 - 数据格式(转)

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.JSON采用完全独立于语言的文本格式,这些特性使JSON成为理想的数据交换语言.易于人阅读和编写,同时也易 ...