环境:Linux x86_64

1、什么是socket

首先socket是在网络编程中的概念。
说到网络,就无法避开OSI模型,或者TCP/IP四层(或三层或五层)模型。
具体的几个层这里就不说了,总之,各个层都定义了一定的数据格式。即协议。

FTP、HTTP、TELNET:应用层协议,传输文本、文件、图片、视频等信息;
—HTTP:从Web服务器传输超文本到本地浏览器的传送协议
TCP/UDP:传输层协议,传输HTTP等协议

网络编程中接触最多的就是在应用层上,编写应用程序,实现两台机器之间的通讯。通讯就是请求/发送数据。
但是应用程序要实现两台机器间的通讯和数据交换:将应用数据发送至另一台机器上。应用层的数据会借助传输层协议来传输,层层向下。

例如,TCP规定了协议内容和定义了数据格式,但是协议属于理论层面,具体到程序开发,还是需要代码实现的。
那么socket在这里的角色就是一一系列编程接口API,应用程序可以通过socket的一些接口函数,实现TCP等协议定义的功能。

socket:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。用"IP+端口号"可以唯一标识一个应用进程,即socket标识。

总结:
socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;
HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
Socket 是对 TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。

2、网络编程要解决的问题

不论是网络编程还是本地编程,都要解决数据交换问题,即通讯问题,想想程序里的变量就是通讯的一种,只不过比较简单。

本地进程间通信:
  消息传递:管道、fifo、消息队列
  同步:互斥量、条件变量、读写锁、文件和写记录锁、信号量
  共享内存:匿名和具名的
  远程过程调用:Solaris门和Sun RPC

网络进程间通信首先要解决如何标识网络中的进程(应用程序)?答案就是使用socket套接字。即使用"ip+端口号"来唯一标识一个进程。

3、socket操作(函数使用)

下面各个函数,可通过Linux的man手册查看:如 man listen

int socket(int domain, int type, int protocol);    //创建一个socket描述符,唯一标识一个socket
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);    //把一个地址族中的特定地址赋给socket
int listen(int sockfd, int backlog);    //调用listen()来监听这个socket,等待客户端的connect()发出连接请求,服务器端就会接收到这个请求。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);    //客户端通过调用connect函数来建立与TCP服务器的连接。addr:server的socket地址
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);    //接收客户端的请求,返回一个已连接的socket描述字

//read, write函数
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

推荐使用recvmsg()/sendmsg()函数,这两个函数是最通用的I/O函数。

//close函数
#include <unistd.h>
int close(int fd);

server调用:
socket() bind()  listen()  accept()
client调用:
socket()  connect()  

例子稍后附上。

4、参考博客

这篇博客写的很好,可以作为socket入门,值得学习。
https://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html
https://www.cnblogs.com/goodcandle/archive/2005/12/10/socket.html

5、demo实例

不知道csdn里的代码如何折叠,所以就放到最后了。。

server.c:

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

#define MAXLINE 4096

int main(int argc, char** argv)
{
        int listenfd, connfd;
        struct sockaddr_in serveraddr;
        char buff[MAXLINE];
        int n, ret;

        if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { // third param is 0,means select default protocol
                printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
                exit(0);
        }

        memset(&serveraddr, 0, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = (inet_addr("10.47.158.12"));  // INADDR_ANY: set addr 0.0.0.0, means all addr
        serveraddr.sin_port = htons(6666);  // htonl: host to nel

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

        if (listen(listenfd, 10) < 0) {
                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)\n", strerror(errno), errno);
                        continue;
                }

                n = recv(connfd, buff, MAXLINE, 0);
                buff[n] = '\0';

                ret = strcmp(buff, "exit\n");
                if (ret == 0)
                        break;
                printf("recv msg from client: %s\n", buff);
                close(connfd);
        }
        close(listenfd);
        return 0;
}

client.c:

#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<arpa/inet.h>

#define MAXLINE 4096

int main(int argc, char** argv)
{
        int socketfd, n;
        struct sockaddr_in serveraddr;
        char recvline[MAXLINE], sendline[MAXLINE];

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

        if ( (socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { // third param is 0,means select default protocol
                printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
                exit(0);
        }

        memset(&serveraddr, 0, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(6666);  // htonl: host to nel=====> htons: host to network u_short!!!
        if (inet_pton(AF_INET, argv[1], &serveraddr.sin_addr) <= 0) {
                printf("inet_pton error for %s \n", argv[1]);
                exit(0);
        }

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

        printf("=========send msg to server.....=====\n");

        while (fgets(sendline, MAXLINE, stdin) != NULL) {
                if (send(socketfd, sendline, strlen(sendline), 0) < 0) {
                        printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
                        exit(0);
                }
        }
        close(socketfd);
        return 0;
}
Logo

更多推荐