一个简单的socket客户端和服务端的例子

本文介绍了Socket在网络编程中的基本概念和作用,它位于应用层和传输层之间,提供TCP/IP通信接口。文章详细讲解了socket的创建、绑定、监听、接受和连接等关键函数,并给出了一个简单的服务端和客户端示例,帮助读者理解和实践Socket编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络编程中最基础的就是socket的操作,这里记录一下socket的基础操作有哪些,分别是什么作用,最后以一个简单的客户端和服务端例子收尾。


socket是什么?

socket起源于Unix,秉承着一切皆文件的思想,socket也是   打开 -读写- 关闭 这样的模式的一个实现。socket用于不同主机间进程的通信,而每个进程由 所使用的协议,Ip,端口号,三者决定,有兴趣的可以百度一下 多路分解和多路复用。


让我们看一下socket在TCP/IP中所处的位置


可以看到,socket位于应用层与传输层之间,作为一层抽象层把tcp/IP的复杂操作抽象成了一些简单的接口供应用层来调用。


socket的基本操作

主要介绍如下几个函数

int socket(int domain , int type, int protocol)

该函数创建一个socket套接字,返回一个socket描述符,相当于对该套接字的引用,在接下来的函数中将会用到它。

我们来看看各个参数,这里只介绍一些楼主使用过的

domain : 协议族,常用的就是AF_INET,AF_INET6,AF_LOCAL等几种(还有不少),它最关键的作用是指定了地址格式,比如说AF_INET(事实上楼主至今也只用了它..),它决定了该socket套接字的地址必须使用 32位的ipv4地址和16位的port号

type :类型,当然指的就是创建的socket类型了,常见的有如下两种,SOCK_STREAM,SOCK_DGRAM(还有不少),分别对应TCP套接字和UDP套接字,至于tcp和udp协议,大家可以去看一下我之前的博文关于tcp和udp的一些事。

protocol: 协议,有IPPROTO_TCP,IPPROTO_UDP等几种(还有不少),显然就是对应于传输层TCP和UDP协议,这里我经常用0,当传入0的时候,会使用socket类型对应的默认传输协议


int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen)

该函数用于给socket绑定一个地址,之前说过了不同的协议族有对应不同的地址,我们以AF_INET,即ipv4+port来解释,先看看sockaddr结构体有哪些成员

struct sockaddr {
        sa_family_t     sa_family;    /* address family, AF_xxx       */
        char            sa_data[14];    /* 14 bytes of protocol address */

}共16个字节

但是我们传入的参数一般是 sockaddr_in结构体,我们来看看sockaddr_in结构体的成员有哪些

struct sockaddr_in
{
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;                     /* Port number. */
    struct in_addr sin_addr;            /* Internet address. */

    /* Pad to size of `struct sockaddr'. */
    unsigned char sin_zero[sizeof (struct sockaddr) -
                           __SOCKADDR_COMMON_SIZE -
                           sizeof (in_port_t) -
                           sizeof (struct in_addr)];     
                           /* 字符数组sin_zero[8]的存在是为了保证结构体struct sockaddr_in的大小和结构体struct sockaddr的大小相等 */
};

其实也就是方便我们使用,可以直接指定ip和port(当然这里有主机字节序和网络字节序的问题),而不需要去操作字符串了


int listen(int sockfd,int backlog)

该函数在服务端编程会用到,用于监听某个端口,至于是哪个就看你传入进去的sockfd设置的是哪一个了,backlog参数用于指定等待连接建立的socket队列的最大长度,成功返回0,失败为-1.

int accept(int sockfd, struct sockaddr* addr,socklen_t addrlen)

该函数返回与客户端建立连接的socket描述符,注意这跟监听socket不同,这是新建的一个用于与客户端通信的socket。该函数会一直阻塞到接收到一个连接为止。

第一个参数是监听socket的描述符,后面2个参数用于接受客户端的地址和地址长度。


上面2个函数都是在服务端编程中用于监听端口,被动创建与客户端的连接时,需要用到的,下面这个函数一般在客户端中需要用到的用于主动创建连接的

int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen )

第一个参数是客户端的socket描述符,第二个参数是服务器的地址,第三个当然还是地址长度,成功的时候返回0,失败则返回-1,该函数在服务器accept后,数据到达时会返回,具体连接过程,可以百度三次握手,也可以看看我写过的tcp的一些事。


OK,连接已经建立好了,现在要进行通讯了,

常用的函数有如下4个

int read(int sockfd,void* buf ,ssize_t count)

int write(int sockfd,void* buf,ssize_t count)

int recv(int sockfd,void* buf,ssize_t count,int flags)

int send(int sockfd,void* buf,ssize_t count,int flags)

这4个函数如何使用,请参照这篇文章http://blog.youkuaiyun.com/u011408355/article/details/45921541

接下来展示一个简单的例子,服务端监听端口,客户端向服务端发起连接,建立连接后客户端发送一句“Client”,服务端接收到后返回一句“Server”。

服务端:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#define PORT 6888
int main()
{
    int listenfd,conndfd;
    struct sockaddr_in  server;
    char buf[2048+1];

    if(-1==(listenfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)))
        printf("Create Socket Error\n");
    memset(&server,0,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_addr.s_addr=inet_addr("127.0.0.1");
    server.sin_port=htons(PORT);
    if(-1==bind(listenfd,(struct sockaddr*)&server,sizeof(server)))
        printf("Bind Error\n");

    printf("Start Listen\n");
    if( -1==listen(listenfd,5)  ){
        printf("Listen Error\n");
        exit(0);
    }
    while(1)
    {
        if( -1==(conndfd=accept(listenfd,NULL,NULL) ))
        {
            printf("Accept Error\n");
            continue;
        }
        memset(buf,0,sizeof(buf));
        int n=recv(conndfd,buf,2048,0);
        printf("Recv msg form cilent, %d byte\n",n);
        printf("%s\n",buf);
        memset(buf,0,sizeof(buf));
        strcpy(buf,"Server");
        send(conndfd,buf,strlen(buf),0);
        close(conndfd);
    }
    close(listenfd);
    return 0;
}



客户端:

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

#define PORT 6888
int main()
{
    int conndfd;
    struct sockaddr_in serverAddr;
    char buf[2048+1];
    if(-1==(conndfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)))
        printf("Create Socket Error\n");
    memset(&serverAddr,0,sizeof(serverAddr));
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    serverAddr.sin_port=htons(PORT);
    if(-1==connect(conndfd,(struct sockaddr*)&serverAddr,sizeof(serverAddr)))
    {
        printf("Connetc Error\n");
        exit(0);
    }
    printf("Connect Success.Lets communicate!\n");
    strcpy(buf,"Client");
    int n=send(conndfd,buf,strlen(buf),0);
    printf("Send %d byte to Server\n",n);
    memset(buf,0,sizeof(buf));
    n=recv(conndfd,buf,2048,0);
    printf("Recv %d byte from Server\n",n);
    printf("%s\n",buf);
    close(conndfd);
    return 0;
}

欢迎大家指正





好的,以下是一个简单的Java Socket客户端和服务例子: 服务代码: ```java import java.io.*; import java.net.*; public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(8080); // 监听8080口 } catch (IOException e) { System.err.println("Could not listen on port: 8080."); System.exit(1); } Socket clientSocket = null; try { System.out.println("Waiting for connection..."); clientSocket = serverSocket.accept(); // 等待客户端连接 System.out.println("Connected to client: " + clientSocket.getInetAddress().getHostName()); } catch (IOException e) { System.err.println("Accept failed."); System.exit(1); } PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("Received from client: " + inputLine); out.println("Server received: " + inputLine); // 发送回复给客户端 } out.close(); in.close(); clientSocket.close(); serverSocket.close(); } } ``` 客户端代码: ```java import java.io.*; import java.net.*; public class Client { public static void main(String[] args) throws IOException { Socket socket = null; PrintWriter out = null; BufferedReader in = null; try { socket = new Socket("localhost", 8080); // 连接到本地8080口 out = new PrintWriter(socket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host: localhost."); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to: localhost."); System.exit(1); } BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String userInput; while ((userInput = stdIn.readLine()) != null) { out.println(userInput); // 发送消息给服务器 System.out.println("Received from server: " + in.readLine()); // 接收服务器的回复 } out.close(); in.close(); stdIn.close(); socket.close(); } } ``` 这个例子中,服务监听8080口,等待客户端连接。一旦客户端连接上来,服务会接收客户端发送的消息,并将收到的消息回复给客户端客户端连接到本地的8080口,向服务发送消息,并接收服务的回复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值