建立一个 TCP 连接时会发生下述情形:

1. 服务器必须准备好接受外来的连接。这通常通过调用 socket、bind 和 listen 这三个函数来完成,我们称之为被动打开。

2. 客户通过调用 connect 发起主动打开,这导致客户TCP发送一个SYN(同步)分节,标识希望连接的服务器端口以及初始序号。通常SYN分节不携带数据,其所在IP数据报只含有一个IP首部、一个TCP首部及可能有的TCP选项。

3. 服务器发送回一个包含服务器初始序号以及对客户端 SYN 段确认的 SYN + ACK 段作为应答,由于一个 SYN 占用一个序号,因此确认序号设置为客户端初始序号加 1。

4. 客户端发送确认序号为服务器初始序号加 1 的 ACK 段,对服务器 SYN 段进行确认。

这种交换至少需要三个分组,因此称之为TCP的三路握手。

一旦TCP建立连接,客户/服务器之间便可以进行数据通信。

1. 服务器端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include <errno.h>
#define PORT 6666 int main(int argc,char **argv)
{
int ser_sockfd,cli_sockfd;
int err,n;
int addlen;
struct sockaddr_in ser_addr;
struct sockaddr_in cli_addr;
char recvline[],sendline[]; ser_sockfd = socket(AF_INET,SOCK_STREAM,); //创建套接字
if(ser_sockfd == -)
{
printf("socket error:%s\n",strerror(errno));
return -;
} bzero(&ser_addr,sizeof(ser_addr)); /*在待捆绑到该TCP套接口(sockfd)的网际套接口地址结构中填入通配地址(INADDR_ANY)
和服务器的众所周知端口(PORT,这里为6666),这里捆绑通配地址是在告知系统:要是系统是
多宿主机(具有多个网络连接的主机),我们将接受宿地址为任何本地接口的地址*/
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ser_addr.sin_port = htons(PORT); //将网际套接口地址结构捆绑到该套接口
err = bind(ser_sockfd,(struct sockaddr *)&ser_addr,sizeof(ser_addr));
if(err == -)
{
printf("bind error:%s\n",strerror(errno));
return -;
}
//将套接口转换为一个监听套接口,监听等待来自客户端的连接请求
err = listen(ser_sockfd,);
if(err == -)
{
printf("listen error\n");
return -;
} printf("listen the port:\n"); while()
{
addlen = sizeof(struct sockaddr);
//等待阻塞,等待客户端申请,并接受客户端的连接请求
//accept成功,将创建一个新的套接字,并为这个新的套接字分配一个套接字描述符
cli_sockfd = accept(ser_sockfd,(struct sockaddr *)&cli_addr,&addlen);
if(cli_sockfd == -)
{
printf("accept error\n");
} //数据传输
while()
{
printf("waiting for client...\n");
n = recv(cli_sockfd,recvline,,);
if(n == -)
{
printf("recv error\n");
}
recvline[n] = '\0'; printf("recv data is:%s\n",recvline); printf("Input your words:");
scanf("%s",sendline);
send(cli_sockfd,sendline,strlen(sendline),);
}
close(cli_sockfd);
}
close(ser_sockfd); return ;
}

1.首先通过 socket 函数创建套接字,此时套接字数据结构字段并未填充,在使用之前必须调用过程来填充对应字段,这里在地址结构中填入通配地址(INADDR_ANY),通配地址就是指定地址为 0.0.0.0 的地址,表示服务器接受机器上所有IP地址的连接,用于多IP机器上。这样无论客户 connect 哪个IP地址,服务器端都会接收到请求,即接受宿地址为任何本地接口的地址。如果是指定地址,那么机器只有 connect 这个地址才能成功。后面是填充端口号,如果指定为 0,则由系统随机选择一个未被使用的端口。

2. bind 将没有指定端口的 socket(ser_sockfd)绑定到我们指定的端口上(通配地址+指定端口号),服务器是通过它们的众所周知端口被大家认识的。这样 socket(ser_sockfd)就与指定的端口产生了关联,即指向了指定端口。

3. listen 将套接口转换为一个监听套接口,被动打开,允许监听客户端的连接请求,然后 accept 客户端的连接请求,没有请求则阻塞。

5. accept 成功后,将创建新的套接字,并为新套接字分配一个套接口描述符,该套接字除了记录本地(服务器)的IP和端口号信息外,还记录了目的(客户)IP和端口号信息。服务器与客户的通信则是通过该新创建的套接字(已连接套接字)进行。

2. 客户端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#define PORT 6666 int main(int argc,char **argv)
{
int sockfd;
int err,n;
struct sockaddr_in addr_ser;
char sendline[],recvline[]; sockfd = socket(AF_INET,SOCK_STREAM,); //创建套接字
if(sockfd == -)
{
printf("socket error\n");
return -;
} bzero(&addr_ser,sizeof(addr_ser)); /*用通配地址和指定端口号装填一个网际接口地址结构*/
addr_ser.sin_family = AF_INET;
addr_ser.sin_addr.s_addr = htonl(INADDR_ANY);
addr_ser.sin_port = htons(PORT); //TCP:客户(sockfd)向服务器(套接口地址结构)发起连接,主动请求
//服务器的IP地址和端口号有参数addr_ser指定
err = connect(sockfd,(struct sockaddr *)&addr_ser,sizeof(addr_ser));
if(err == -)
{
printf("connect error\n");
return -;
} printf("connect with server...\n"); //数据传输
while()
{
printf("Input your words:");
scanf("%s",sendline); send(sockfd,sendline,strlen(sendline),); printf("waiting for server...\n"); n = recv(sockfd,recvline,,);
recvline[n] = '\0'; printf("recv data is:%s\n",recvline);
} return ;
}

1. 客户端同样通过 socket 创建套接字,TCP 客户通常不把IP地址捆绑到它的套接口上,当连接套接口时,内核将根据所用外出网络接口来确定源IP地址,并选择一个临时端口作为源端口。
2. 用通配地址和指定端口填充的是待连接服务器端的套接字地址结购,这里采用的是通配地址,由于服务器端指定的是通配地址,即接受机器上所有IP地址的连接,同样客户也可向机器上任何IP地址发起连接,服务器端都会接收到。

3. 客户端向服务器发起连接请求,connect 成功后,其请求连接的服务器的IP和端口号信息将会写入该套接字,这样该套接字也同时记录了本地和目的的IP地址和端口信息。也就可以进行通信了。

结果如下:

【Unix 网络编程】TCP 客户/服务器简单 Socket 程序的更多相关文章

  1. TCP客户/服务器简单Socket程序

    建立一个 TCP 连接时会发生下述情形: 1. 服务器必须准备好接受外来的连接.这通常通过调用 socket.bind 和 listen 这三个函数来完成,我们称之为被动打开. 2. 客户通过调用 c ...

  2. UNIX网络编程---TCP客户/服务器程序示例(五)

    一.概述 客户从标准输入读入一行文本,并写给服务器 服务器从网络输入读入这行文本,并回射给客户 客户从网络输入读入这行回射文本,并显示在标准输出上 二.TCP回射服务器程序:main函数 这里给了函数 ...

  3. 3.网络编程-tcp的服务器简单实现

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2019/1/13 22:03 # @Author : ChenAdong # @ema ...

  4. 第5章-unix网络编程 TCP/服务端程序示例

    这一章主要是完成一个完整的tcp客户/服务器程序.通过一很简单的例子.弄清客户和服务器如何启动,如何终止,发生了某些错误会发生什么.这些事很重要的  客户端代码 #include "unp. ...

  5. unix网络编程——TCP套接字编程

    TCP客户端和服务端所需的基本套接字.服务器先启动,之后的某个时刻客户端启动并试图连接到服务器.之后客户端向服务器发送请求,服务器处理请求,并给客户端一个响应.该过程一直持续下去,直到客户端关闭,给服 ...

  6. Linux网络编程——tcp并发服务器(poll实现)

    想详细彻底地了解poll或看懂下面的代码请参考<Linux网络编程——I/O复用之poll函数> 代码: #include <string.h> #include <st ...

  7. JAVA基础知识之网络编程——-TCP/IP协议,socket通信,服务器客户端通信demo

    OSI模型分层 OSI模型是指国际标准化组织(ISO)提出的开放系统互连参考模型(Open System Interconnection Reference Model,OSI/RM),它将网络分为七 ...

  8. UNIX网络编程——TCP回射服务器/客户端程序

    下面通过最简单的客户端/服务器程序的实例来学习socket API. serv.c 程序的功能是从客户端读取字符然后直接回射回去: #include<stdio.h> #include&l ...

  9. UNIX网络编程——TCP服务器“拒绝服务攻击” 解决方案

    前面的博客<<使用select和shutdown>>里面的拒绝服务型攻击也有提到. 说这是一个完全的解决方案,其实有点夸大了,但这个方案确实可以缓解TCP服务器遭受" ...

随机推荐

  1. angular2 引入jquery

    (注:以下命令都是在项目文件夹根目录下运行的,保证下载的文件都在项目的node_modules文件夹里面) 1. 运行  npm install jquery -save 后会发现在package.j ...

  2. 网络I/O模型--03非阻塞模式(ServerSocket与Socket的超时处理)--解除accept()、 read()方法阻塞

    对于阻塞方式的一种改进是在应用程序层面上将 “一直等待 ”的状态主动打开: 这种模式下,应用程序的线程不再一直等待操作系统的 I/O状态,而是在等待一段时间后就解除阻塞.如果没有得到想要的结果,则再次 ...

  3. ReactNative应用<DCL每日查看>开发总结

    App效果: 功能和交互简单描述: 针对微信使用用户每天的零碎时间来进行天气,新闻要点等查看,免去了打开其他App来查看; 针对每一天可以设置一项重要任务计划,可开启通知提醒,让每一天任务简化,免去太 ...

  4. hue简单介绍

    hue定义: HUE=Hadoop User Experience 个人理解:可视图的webui界面,方便大数据技术之间的CRUD操作. 官方定义:Hue是一个能够与Apache Hadoop交互的W ...

  5. 回归JavaScript基础(九)

    主题:理解对象,创建对象. 小明是一名程序猿,也是一条单身狗!他常常自嘲:每天都会有很多对象,但却没有女朋友! 多么痛的领悟.哈哈,目前比较流行的编程语言都是面向对象的语言(Object-Orient ...

  6. Oracle EBS 跳跳转标准销售订单程序转标准销售订单程序

    -- 打开PO PROCEDURE Btn_Open_Po IS BEGIN Fnd_Function.Execute(Function_Name => 'PO_POXPOEPO', Open_ ...

  7. REST Framework 的用户认证组件

    用户认证流程: 我们要知道这个流程是怎么走的? 认证之后做的什么? 怎么认证?这三个条件 认证流程:就是使用BaseAuthentication这个模块来做认证,判断你登陆成功传递过来的随机字符串是否 ...

  8. [翻译] CSStickyHeaderFlowLayout

    CSStickyHeaderFlowLayout https://github.com/jamztang/CSStickyHeaderFlowLayout Parallax, Sticky Heade ...

  9. AFNetworking2.0简易GET,POST请求封装以及使用

    AFNetworking2.0简易GET,POST请求封装以及使用 AFNetworking不用我赘述其强大性,本人仅仅做了非常简易的封装,解决了有时候请求出错的问题,提供源码给大家. 封装源码库下载 ...

  10. [翻译] DDExpandableButton

    DDExpandableButton https://github.com/ddebin/DDExpandableButton Purpose - 目的 DDExpandableButton is a ...