1. 先介绍一些用到的函数

1)包含头文件<sys/socket.h>
功能:创建一个套接字用于通信
原型
int socket(int domain, int type, int protocol);
参数
domain :指定通信协议族(protocol family)
type:指定socket类型,流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW
protocol :协议类型
返回值:成功返回非负整数, 它与文件描述符类似,我们把它称为套接口描述字,简称套接字。失败返回-1


2)包含头文件<sys/socket.h>
功能:绑定一个本地地址到套接字
原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数
sockfd:socket函数返回的套接字
addr:要绑定的地址
addrlen:地址长度
返回值:成功返回0,失败返回-1



3)包含头文件<sys/socket.h>
功能:将套接字用于监听进入的连接
原型
int listen(int sockfd, int backlog);
参数
sockfd:socket函数返回的套接字
backlog:规定内核为此套接字排队的最大连接个数
返回值:成功返回0,失败返回-1
一般来说,listen函数应该在调用socket和bind函数之后,调用函数accept之前调用。
对于给定的监听套接口,内核要维护两个队列:
1、已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程
2、已完成连接的队列


4)包含头文件<sys/socket.h>
功能:从已完成连接队列返回第一个连接,如果已完成连接队列为空,则阻塞。
原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数
sockfd:服务器套接字
addr:将返回对等方的套接字地址
addrlen:返回对等方的套接字地址长度
返回值:成功返回非负整数,失败返回-1

5)包含头文件<sys/socket.h>
功能:建立一个连接至addr所指定的套接字
原型
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数
sockfd:未连接套接字
addr:要连接的套接字地址
addrlen:第二个参数addr长度
返回值:成功返回0,失败返回-1
 

 

2. 头文件 ../apue.h
#ifndef _APUE_H_
#define _APUE_H_

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <signal.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h>

void err_exit(char *m){
        perror(m);
        exit(EXIT_FAILURE);
}

 

3. 服务器主程序, 此程序同时只能处理一个客户端请求

#include "../apue.h"

int main(void){
        int listenfd;
        listenfd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(listenfd < 0)
                err_exit("listen error");

        struct sockaddr_in servaddr;
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(5188);
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        //servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        //inet_aton("127.0.0.1", $servaddr.sin_addr);

       //以上三种赋值方式意义相近

        if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))<0)
                err_exit("bind error");

        if(listen(listenfd, SOMAXCONN)<0)
                err_exit("listen error");

        struct sockaddr_in peeraddr;
        socklen_t peerlen = sizeof(peeraddr);
        int conn;
        if((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen))<0)
                err_exit("accept error");
        char buf[1024];
        int ret;
        while (1){
                memset(buf, 0, sizeof(buf));
                ret = read(conn, buf, sizeof(buf));
                fputs(buf, stdout);
                write(conn, buf, ret);
        }
        return 0;
}

 

 

4. 客户端程序

#include "../apue.h"

int main(void){
        int socketfd;
        socketfd = socket(AF_INET, SOCK_STREAM, 0);
        if(socketfd == -1)
                err_exit("socket error");

        struct sockaddr_in clientaddr;
        memset(&clientaddr, 0, sizeof(clientaddr));
        clientaddr.sin_family = AF_INET;
        clientaddr.sin_port = htons(5188);
        clientaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

        int conn;
        conn = connect(socketfd, (struct sockaddr*)&clientaddr, sizeof(clientaddr));
        if(conn == -1)
                err_exit("connect error");
        char recvbuf[1024] = {0};
    char sendbuf[1024] = {0};
    while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL){
        write(socketfd, sendbuf, sizeof(sendbuf));
                read(socketfd, recvbuf, sizeof(recvbuf));
                fputs(recvbuf,stdout);

    }
        close(socketfd);
        return 0;
}