socket详解

socket网络编程
1.进程间如何通信
本地进程间通信我们知道有以下几种方式:
1)消息传递(管道,FIFO,消息队列)
管道是一个进程的数据流到另一个进程的通道,即一个进程的数据输出作为另一个进程的数据输入,管道起到了桥梁的作用。
2)共享内存
不同进程访问同一个逻辑内存
3)同步
互斥量,条件变量,读写锁,信号量
4)远程过程调用
但是网络间的进程是如何通信的呢?如浏览器进程如何与web服务器通信,QQ聊天时,QQ进程如何与服务器或你好友所在的QQ进程通信?
答案是socket,网络间的进程通信几乎都是用的socket.

2.如何识别网络中唯一进程
本地进程间可以通过PID来唯一标识一个进程
网络中我们根据TCP/IP协议族来标识唯一进程,网络层的“IP地址”可唯一标识网络中的主机,而传输层的“协议+端口”可唯一标识主机中的进程。“IP地址+协议+端口”就可以确定唯一进程了。
3.进程间如何通过socket进行通讯
Linux的哲学是一切皆文件,socket也是一种文件。可以使用“打开-读写-关闭”来操作。socket是应用层和运输层之间的一个抽象层。
socket通信流程:
1)服务端创建socket
socket()
2)服务端绑定端口号
bind()
3)服务端监听端口号
listen()
4)客户端创建socket
socket()
5)客户端主动打开socket,连接服务器端socket
connect()
6)服务端接收客户端请求,socket被动打开
同步:accept() 异步:beginaccept()
7)客户端socket向服务端socket写信息
send()
8)服务端socket读取信息
9)客户端socket关闭
10)服务端socket关闭

4.socket建立连接的三次握手

 

第一步,客户端调用connect,向服务器发送SYN J包,connect阻塞
第二步,服务端收到SYN J包,调用accept函数接收请求,向客户端发送 SYN K,ACK J+1
        accept函数阻塞
第三步,客户端收到服务器的SYN K,ACK J+1后,connect返回,进行SYN K确认,服务端收到ACK K+1时,accept返回,三次握手完成,连接建立。

5.socket释放连接的四次握手


第一步,客户端关闭连接,发送一个FIN M到服务端
第二步,服务端接收到FIN M后,执行被动关闭,对这个FIN M进行确认ACK M+1。
第三步,当服务端发送完毕后,再发送FIN N到客户端
第四步,客户端接收到FIN N调用close关闭它的socket,发送一个ACK N+1到服务端
服务端接收到这个ACK N+1关闭它的socket

6.为什么建立连接是三次握手,释放连接需要四次
这是因为进行释放连接的第二步时,有可能服务端仍有数据发送给客户端,因此,需要分开,先对客户端FIN报文应答,当服务端数据发送完毕后,再发送FIN报文到客户端。

7.socket连接示例
服务器端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

#define MAXLINE 4096

int main(int argc, char** argv)
{
    int    listenfd, connfd;
    struct sockaddr_in     servaddr;
    char    buff[4096];
    int     n;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
    printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(6666);

    if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
    printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }

    if( listen(listenfd, 10) == -1){
    printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }

    printf("======waiting for client's request======\n");
    while(1){
    if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
        printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
        continue;
    }
    n = recv(connfd, buff, MAXLINE, 0);
    buff[n] = '\0';
    printf("recv msg from client: %s\n", buff);
    close(connfd);
    }

    close(listenfd);
}

客户端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

#define MAXLINE 4096

int main(int argc, char** argv)
{
    int    sockfd, n;
    char    recvline[4096], sendline[4096];
    struct sockaddr_in    servaddr;

    if( argc != 2){
    printf("usage: ./client <ipaddress>\n");
    exit(0);
    }

    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
    exit(0);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(6666);
    if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
    printf("inet_pton error for %s\n",argv[1]);
    exit(0);
    }

    if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
    printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }

    printf("send msg to server: \n");
    fgets(sendline, 4096, stdin);
    if( send(sockfd, sendline, strlen(sendline), 0) < 0)
    {
    printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
    exit(0);
    }

    close(sockfd);
    exit(0);
}

 

posted on 2016-12-02 21:39  迪米特  阅读(899)  评论(0编辑  收藏  举报

导航