当前位置: 首页 > news >正文

代做网站跳转企业宽带

代做网站跳转,企业宽带,那些做seo的网站,局域网内用自己电脑做网站文章目录 前言一、socket的基本操作(1) socket()函数(2) bind()函数(3) listen()、connect()函数(4) accept()函数(5) read()、write()等函数(6) close()函数 二、smallchat代码流程smallchat-server.csmallchat-client.cchatlib.c 参考资料 前言 本文介绍了socket通信的相关A… 文章目录 前言一、socket的基本操作(1) socket()函数(2) bind()函数(3) listen()、connect()函数(4) accept()函数(5) read()、write()等函数(6) close()函数 二、smallchat代码流程smallchat-server.csmallchat-client.cchatlib.c 参考资料 前言 本文介绍了socket通信的相关API以及Redis 创始人 antirez 用纯 C 语言代码写了一个聊天服务器的最小编程示例Smallchat。 一、socket的基本操作 socket是“open—write/read—close”模式的一种实现下面以TCP为例介绍几个基本的socket接口函数。 (1) socket()函数 int socket(int family, int type, int protocol);socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字而socket()用于创建一个socket描述符(socket descriptor)它唯一标识一个socket。这个socket描述字跟文件描述字一样后续的操作都有用到它把它作为参数通过它来进行一些读写操作。 正如可以给fopen的传入不同参数值以打开不同的文件。创建socket的时候也可以指定不同的参数创建不同的socket描述符socket函数的三个参数分别为 domain即协议域又称为协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIXUnix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型在通信中必须采用对应的地址如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。type指定socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。protocol故名思意就是指定协议。常用的协议有IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议(这个协议我将会单独开篇讨论!)。 注意并不是上面的type和protocol可以随意组合的如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时会自动选择type类型对应的默认协议。 当我们调用socket创建一个socket时返回的socket描述字它存在于协议族(address familyAF_XXX)空间中但没有一个具体的地址。如果想要给它赋值一个地址就必须调用bind()函数否则就当调用connect()、listen()时系统会自动随机分配一个端口。 (2) bind()函数 正如上面所说bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。 int bind(int sockfd, struct sockaddr *my_addr, int addrlen);函数的三个参数分别为 sockfd即socket描述字它是通过socket()函数创建了唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。addr一个const struct sockaddr *指针指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同如ipv4对应的是 struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ }; addrlen对应的是地址的长度。 通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址端口号)用于提供服务客户就可以通过它来接连服务器;而客户端就不用指定有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind()而客户端就不会调用而是在connect()时由系统随机生成一个。 网络字节序与主机字节序 主机字节序就是我们平常说的大端和小端模式不同的CPU有不同的字节序类型这些字节序是指整数在内存中保存的顺序这个叫做主机序。引用标准的Big-Endian和Little-Endian的定义如下 Little-Endian就是低位字节排放在内存的低地址端高位字节排放在内存的高地址端。Big-Endian就是高位字节排放在内存的低地址端低位字节排放在内存的高地址端。 网络字节序4个字节的32 bit值以下面的次序传输首先是07bit其次815bit然后1623bit最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序因此它又称作网络字节序。字节序顾名思义字节的顺序就是大于一个字节类型的数据在内存中的存放顺序一个字节的数据没有顺序的问题了。 所以在将一个地址绑定到socket的时候请先将主机字节序转换成为网络字节序而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。由于这个问题曾引发过血案!公司项目代码中由于存在这个问题导致了很多莫名其妙的问题所以请谨记对主机字节序不要做任何假定务必将其转化为网络字节序再赋给socket。 (3) listen()、connect()函数 如果作为一个服务器在调用socket()、bind()之后就会调用listen()来监听这个socket如果客户端这时调用connect()发出连接请求服务器端就会接收到这个请求。 int listen(int sockfd, int backlog); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); listen函数的第一个参数即为要监听的socket描述字第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的listen函数将socket变为被动类型的等待客户的连接请求。 connect函数的第一个参数即为客户端的socket描述字第二参数为服务器的socket地址第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。 (4) accept()函数 TCP服务器端依次调用socket()、bind()、listen()之后就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后就会调用accept()函数取接收请求这样连接就建立好了。之后就可以开始网络I/O操作了即类同于普通文件的读写I/O操作。 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); accept函数的第一个参数为服务器的socket描述字第二个参数为指向struct sockaddr *的指针用于返回客户端的协议地址第三个参数为协议地址的长度。如果accpet成功那么其返回值是由内核自动生成的一个全新的描述字代表与返回客户的TCP连接。 (5) read()、write()等函数 万事具备只欠东风至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了即实现了网咯中不同进程之间的通信!网络I/O操作有下面几组 read()/write() recv()/send() readv()/writev() recvmsg()/sendmsg() recvfrom()/sendto()我推荐使用recvmsg()/sendmsg()函数这两个函数是最通用的I/O函数实际上可以把上面的其它函数都替换成这两个函数。它们的声明如下 #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 recv(int sockfd, void *buf, size_t len, int flags); ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); read函数是负责从fd中读取内容.当读成功时read返回实际所读的字节数如果返回的值是0表示已经读到文件的结束了小于0表示出现了错误。如果错误为EINTR说明读是由中断引起的如果是ECONNREST表示网络连接出了问题。 write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数。失败时返回-1并设置errno变量。 在网络程序中当我们向套接字文件描述符写时有俩种可能。 1)write的返回值大于0表示写了部分或者是全部的数据。 2)返回的值小于0此时出现了错误。我们要根据错误类型来处理。如果错误为EINTR表示在写的时候出现了中断错误。如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接)。 (6) close()函数 在服务器与客户端建立连接之后会进行一些读写操作完成了读写操作就要关闭相应的socket描述字好比操作完打开的文件要调用fclose关闭打开的文件。 #include unistd.h int close(int fd);close一个TCP socket的缺省行为时把该socket标记为以关闭然后立即返回到调用进程。该描述字不能再由调用进程使用也就是说不能再作为read或write的第一个参数。 注意close操作只是使相应socket描述字的引用计数-1只有当引用计数为0的时候才会触发TCP客户端向服务器发送终止连接请求。 二、smallchat Smallchat 源代码已托管至 GitHubhttps://github.com/antirez/smal antirez 表示编写这个示例是为了帮助他的前端开发朋友了解系统编程知识比如单个进程执行多路复用、获取客户端状态并在客户端拥有新数据后尝试快速访问此类状态等等。 代码流程 1.initChat初始化全局变量同时创建服务端监听fd保存到全局变量Chat-serversock中 2.开始while死循环 3.先初始化fd_set集合 4.将监听fd和客户端fd放入到fd_set集合中 5.调用系统函数select对fd_set集合进行事件监测同时将监测到结果保存到fd_set中 6.最后在分别对监听fd和客户端fd在结果fd_set中是否有事件进行判断 7.分别进行对应的业务处理smallchat-server.c /* smallchat.c -- Read clients input, send to all the other connected clients.** Copyright (c) 2023, Salvatore Sanfilippo antirez at gmail dot com* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:** * Redistributions of source code must retain the above copyright notice,* this list of conditions and the following disclaimer.* * Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentation and/or other materials provided with the distribution.* * Neither the project name of nor the names of its contributors may be used* to endorse or promote products derived from this software without* specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*/#include stdio.h #include string.h #include stdlib.h #include assert.h #include sys/select.h #include unistd.h#include chatlib.h/* Data structures * The minimal stuff we can afford to have. This example must be simple* even for people that dont know a lot of C.* */#define MAX_CLIENTS 1000 // This is actually the higher file descriptor. #define SERVER_PORT 7711/* This structure represents a connected client. There is very little* info about it: the socket descriptor and the nick name, if set, otherwise* the first byte of the nickname is set to 0 if not set.* The client can set its nickname with /nick nickname command. */ struct client {int fd; // Client socket.char *nick; // Nickname of the client. };/* This global structure encapsulates the global state of the chat. */ struct chatState {int serversock; // Listening server socket.int numclients; // Number of connected clients right now.int maxclient; // The greatest clients slot populated.struct client *clients[MAX_CLIENTS]; // Clients are set in the corresponding// slot of their socket descriptor. };struct chatState *Chat; // Initialized at startup./* Small chat core implementation * Here the idea is very simple: we accept new connections, read what clients* write us and fan-out (that is, send-to-all) the message to everybody* with the exception of the sender. And that is, of course, the most* simple chat system ever possible.* *//* Create a new client bound to fd. This is called when a new client* connects. As a side effect updates the global Chat state. */ struct client *createClient(int fd) {char nick[32]; // Used to create an initial nick for the user.int nicklen snprintf(nick,sizeof(nick),user:%d,fd);struct client *c chatMalloc(sizeof(*c));socketSetNonBlockNoDelay(fd); // Pretend this will not fail.c-fd fd;c-nick chatMalloc(nicklen1);memcpy(c-nick,nick,nicklen);assert(Chat-clients[c-fd] NULL); // This should be available.Chat-clients[c-fd] c;/* We need to update the max client set if needed. */if (c-fd Chat-maxclient) Chat-maxclient c-fd;Chat-numclients;return c; }/* Free a client, associated resources, and unbind it from the global* state in Chat. */ void freeClient(struct client *c) {free(c-nick);close(c-fd);Chat-clients[c-fd] NULL;Chat-numclients--;if (Chat-maxclient c-fd) {/* Ooops, this was the max client set. Lets find what is* the new highest slot used. */int j;for (j Chat-maxclient-1; j 0; j--) {if (Chat-clients[j] ! NULL) {Chat-maxclient j;break;}}if (j -1) Chat-maxclient -1; // We no longer have clients.}free(c); }/* Allocate and init the global stuff. */ void initChat(void) {Chat chatMalloc(sizeof(*Chat)); // 封装了一层malloc申请内存失败时直接退出程序了memset(Chat,0,sizeof(*Chat));/* No clients at startup, of course. */Chat-maxclient -1;Chat-numclients 0;/* Create our listening socket, bound to the given port. This* is where our clients will connect. */Chat-serversock createTCPServer(SERVER_PORT);if (Chat-serversock -1) {perror(Creating listening socket);exit(1);} }/* Send the specified string to all connected clients but the one* having as socket descriptor excluded. If you want to send something* to every client just set excluded to an impossible socket: -1. */ void sendMsgToAllClientsBut(int excluded, char *s, size_t len) {for (int j 0; j Chat-maxclient; j) {if (Chat-clients[j] NULL ||Chat-clients[j]-fd excluded) continue;/* Important: we dont do ANY BUFFERING. We just use the kernel* socket buffers. If the content does not fit, we dont care.* This is needed in order to keep this program simple. */write(Chat-clients[j]-fd,s,len);} }/* The main() function implements the main chat logic:* 1. Accept new clients connections if any.* 2. Check if any client sent us some new message.* 3. Send the message to all the other clients. */ int main(void) {initChat();while(1) {fd_set readfds;struct timeval tv;int retval;FD_ZERO(readfds); // 初始化文件描述符集/* When we want to be notified by select() that there is* activity? If the listening socket has pending clients to accept* or if any other client wrote anything. */FD_SET(Chat-serversock, readfds); // 将文件描述符加入集合for (int j 0; j Chat-maxclient; j) {if (Chat-clients[j]) FD_SET(j, readfds);}/* Set a timeout for select(), see later why this may be useful* in the future (not now). */tv.tv_sec 1; // 1 sec timeouttv.tv_usec 0;/* Select wants as first argument the maximum file descriptor* in use plus one. It can be either one of our clients or the* server socket itself. */int maxfd Chat-maxclient;if (maxfd Chat-serversock) maxfd Chat-serversock;retval select(maxfd1, readfds, NULL, NULL, tv);if (retval -1) {perror(select() error);exit(1);} else if (retval) {/* If the listening socket is readable, it actually means* there are new clients connections pending to accept. */if (FD_ISSET(Chat-serversock, readfds)) {int fd acceptClient(Chat-serversock);struct client *c createClient(fd);/* Send a welcome message. */char *welcome_msg Welcome to Simple Chat! Use /nick nick to set your nick.\n;write(c-fd,welcome_msg,strlen(welcome_msg));printf(Connected client fd%d\n, fd);}/* Here for each connected client, check if there are pending* data the client sent us. */char readbuf[256];for (int j 0; j Chat-maxclient; j) {if (Chat-clients[j] NULL) continue;if (FD_ISSET(j, readfds)) {/* Here we just hope that there is a well formed* message waiting for us. But it is entirely possible* that we read just half a message. In a normal program* that is not designed to be that simple, we should try* to buffer reads until the end-of-the-line is reached. */int nread read(j,readbuf,sizeof(readbuf)-1);if (nread 0) {/* Error or short read means that the socket* was closed. */printf(Disconnected client fd%d, nick%s\n,j, Chat-clients[j]-nick);freeClient(Chat-clients[j]);} else {/* The client sent us a message. We need to* relay this message to all the other clients* in the chat. */struct client *c Chat-clients[j];readbuf[nread] 0;/* If the user message starts with /, we* process it as a client command. So far* only the /nick newnick command is implemented. */if (readbuf[0] /) {/* Remove any trailing newline. */char *p;p strchr(readbuf,\r); if (p) *p 0;p strchr(readbuf,\n); if (p) *p 0;/* Check for an argument of the command, after* the space. */char *arg strchr(readbuf, );if (arg) {*arg 0; /* Terminate command name. */arg; /* Argument is 1 byte after the space. */}if (!strcmp(readbuf,/nick) arg) {free(c-nick);int nicklen strlen(arg);c-nick chatMalloc(nicklen1);memcpy(c-nick,arg,nicklen1);} else {/* Unsupported command. Send an error. */char *errmsg Unsupported command\n;write(c-fd,errmsg,strlen(errmsg));}} else {/* Create a message to send everybody (and show* on the server console) in the form:* nick some message. */char msg[256];int msglen snprintf(msg, sizeof(msg),%s %s, c-nick, readbuf);/* snprintf() return value may be larger than* sizeof(msg) in case there is no room for the* whole output. */if (msglen (int)sizeof(msg))msglen sizeof(msg)-1;printf(%s,msg);/* Send it to all the other clients. */sendMsgToAllClientsBut(j,msg,msglen);}}}}} else {/* Timeout occurred. We dont do anything right now, but in* general this section can be used to wakeup periodically* even if there is no clients activity. */}}return 0; }smallchat-client.c /* smallchat-client.c -- Client program for smallchat-server.** Copyright (c) 2023, Salvatore Sanfilippo antirez at gmail dot com* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:** * Redistributions of source code must retain the above copyright notice,* this list of conditions and the following disclaimer.* * Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentation and/or other materials provided with the distribution.* * Neither the project name of nor the names of its contributors may be used* to endorse or promote products derived from this software without* specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*/#include stdio.h #include string.h #include stdlib.h #include assert.h #include sys/select.h #include unistd.h #include termios.h #include errno.h#include chatlib.h/* * Low level terminal handling.* */void disableRawModeAtExit(void);/* Raw mode: 1960 magic shit. */ int setRawMode(int fd, int enable) {/* We have a bit of global state (but local in scope) here.* This is needed to correctly set/undo raw mode. */static struct termios orig_termios; // Save original terminal status here.static int atexit_registered 0; // Avoid registering atexit() many times.static int rawmode_is_set 0; // True if raw mode was enabled.struct termios raw;/* If enable is zero, we just have to disable raw mode if it is* currently set. */if (enable 0) {/* Dont even check the return value as its too late. */if (rawmode_is_set tcsetattr(fd,TCSAFLUSH,orig_termios) ! -1)rawmode_is_set 0;return 0;}/* Enable raw mode. */if (!isatty(fd)) goto fatal;if (!atexit_registered) {atexit(disableRawModeAtExit);atexit_registered 1;}if (tcgetattr(fd,orig_termios) -1) goto fatal;raw orig_termios; /* modify the original mode *//* input modes: no break, no CR to NL, no parity check, no strip char,* no start/stop output control. */raw.c_iflag ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);/* output modes - do nothing. We want post processing enabled so that* \n will be automatically translated to \r\n. */// raw.c_oflag .../* control modes - set 8 bit chars */raw.c_cflag | (CS8);/* local modes - choing off, canonical off, no extended functions,* but take signal chars (^Z,^C) enabled. */raw.c_lflag ~(ECHO | ICANON | IEXTEN);/* control chars - set return condition: min number of bytes and timer.* We want read to return every single byte, without timeout. */raw.c_cc[VMIN] 1; raw.c_cc[VTIME] 0; /* 1 byte, no timer *//* put terminal in raw mode after flushing */if (tcsetattr(fd,TCSAFLUSH,raw) 0) goto fatal;rawmode_is_set 1;return 0;fatal:errno ENOTTY;return -1; }/* At exit well try to fix the terminal to the initial conditions. */ void disableRawModeAtExit(void) {setRawMode(STDIN_FILENO,0); }/* * Mininal line editing.* */void terminalCleanCurrentLine(void) {write(fileno(stdout),\e[2K,4); }void terminalCursorAtLineStart(void) {write(fileno(stdout),\r,1); }#define IB_MAX 128 struct InputBuffer {char buf[IB_MAX]; // Buffer holding the data.int len; // Current length. };/* inputBuffer*() return values: */ #define IB_ERR 0 // Sorry, unable to comply. #define IB_OK 1 // Ok, got the new char, did the operation, ... #define IB_GOTLINE 2 // Hey, now there is a well formed line to read./* Append the specified character to the buffer. */ int inputBufferAppend(struct InputBuffer *ib, int c) {if (ib-len IB_MAX) return IB_ERR; // No room.ib-buf[ib-len] c;ib-len;return IB_OK; }void inputBufferHide(struct InputBuffer *ib); void inputBufferShow(struct InputBuffer *ib);/* Process every new keystroke arriving from the keyboard. As a side effect* the input buffer state is modified in order to reflect the current line* the user is typing, so that reading the input buffer buf for len* bytes will contain it. */ int inputBufferFeedChar(struct InputBuffer *ib, int c) {switch(c) {case \n:break; // Ignored. We handle \r instead.case \r:return IB_GOTLINE;case 127: // Backspace.if (ib-len 0) {ib-len--;inputBufferHide(ib);inputBufferShow(ib);}break;default:if (inputBufferAppend(ib,c) IB_OK)write(fileno(stdout),ib-bufib-len-1,1);break;}return IB_OK; }/* Hide the line the user is typing. */ void inputBufferHide(struct InputBuffer *ib) {(void)ib; // Not used var, but is conceptually part of the API.terminalCleanCurrentLine();terminalCursorAtLineStart(); }/* Show again the current line. Usually called after InputBufferHide(). */ void inputBufferShow(struct InputBuffer *ib) {write(fileno(stdout),ib-buf,ib-len); }/* Reset the buffer to be empty. */ void inputBufferClear(struct InputBuffer *ib) {ib-len 0;inputBufferHide(ib); }/* * Main program logic, finally :)* */int main(int argc, char **argv) {if (argc ! 3) {printf(Usage: %s host port\n, argv[0]);exit(1);}/* Create a TCP connection with the server. */int s TCPConnect(argv[1],atoi(argv[2]),0);if (s -1) {perror(Connecting to server);exit(1);}/* Put the terminal in raw mode: this way we will receive every* single key stroke as soon as the user types it. No buffering* nor translation of escape sequences of any kind. */setRawMode(fileno(stdin),1); // 获取标准输入流 stdin 的文件描述符/* Wait for the standard input or the server socket to* have some data. */fd_set readfds;int stdin_fd fileno(stdin);struct InputBuffer ib;inputBufferClear(ib);while(1) {FD_ZERO(readfds);FD_SET(s, readfds);FD_SET(stdin_fd, readfds);int maxfd s stdin_fd ? s : stdin_fd;int num_events select(maxfd1, readfds, NULL, NULL, NULL);if (num_events -1) {perror(select() error);exit(1);} else if (num_events) {char buf[128]; /* Generic buffer for both code paths. */if (FD_ISSET(s, readfds)) {/* Data from the server? */ssize_t count read(s,buf,sizeof(buf));if (count 0) {printf(Connection lost\n);exit(1);}inputBufferHide(ib);write(fileno(stdout),buf,count);inputBufferShow(ib);} else if (FD_ISSET(stdin_fd, readfds)) {/* Data from the user typing on the terminal? */ssize_t count read(stdin_fd,buf,sizeof(buf));for (int j 0; j count; j) {int res inputBufferFeedChar(ib,buf[j]);switch(res) {case IB_GOTLINE:inputBufferAppend(ib,\n);inputBufferHide(ib);write(fileno(stdout),you , 5);write(fileno(stdout),ib.buf,ib.len);write(s,ib.buf,ib.len);inputBufferClear(ib);break;case IB_OK:break;}}}}}close(s);return 0; } chatlib.c #define _POSIX_C_SOURCE 200112L #include sys/types.h #include sys/socket.h #include netinet/in.h #include netinet/tcp.h #include arpa/inet.h #include unistd.h #include fcntl.h #include netdb.h #include errno.h #include stdio.h #include stdlib.h #include string.h/* Low level networking stuff * Here you will find basic socket stuff that should be part of* a decent standard C library, but you know... there are other* crazy goals for the future of C: like to make the whole language an* Undefined Behavior.* *//* Set the specified socket in non-blocking mode, with no delay flag. */ int socketSetNonBlockNoDelay(int fd) {int flags, yes 1;/* Set the socket nonblocking.* Note that fcntl(2) for F_GETFL and F_SETFL cant be* interrupted by a signal. */if ((flags fcntl(fd, F_GETFL)) -1) return -1; // 获取套接字当前的文件状态标志if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) -1) return -1; // 将套接字设置为非阻塞模式/* This is best-effort. No need to check for errors. */setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, yes, sizeof(yes));return 0; }/* Create a TCP socket listening to port ready to accept connections. */ int createTCPServer(int port) {int s, yes 1;struct sockaddr_in sa;if ((s socket(AF_INET, SOCK_STREAM, 0)) -1) return -1;setsockopt(s, SOL_SOCKET, SO_REUSEADDR, yes, sizeof(yes)); // Best effort.memset(sa,0,sizeof(sa));sa.sin_family AF_INET;sa.sin_port htons(port);sa.sin_addr.s_addr htonl(INADDR_ANY); // INADDR_ANY表示服务器将监听所有网络接口上的连接请求if (bind(s,(struct sockaddr*)sa,sizeof(sa)) -1 ||listen(s, 511) -1){close(s);return -1;}return s; }/* Create a TCP socket and connect it to the specified address.* On success the socket descriptor is returned, otherwise -1.** If nonblock is non-zero, the socket is put in nonblocking state* and the connect() attempt will not block as well, but the socket* may not be immediately ready for writing. */ int TCPConnect(char *addr, int port, int nonblock) {int s, retval -1;struct addrinfo hints, *servinfo, *p;char portstr[6]; /* Max 16 bit number string length. */snprintf(portstr,sizeof(portstr),%d,port);memset(hints,0,sizeof(hints));hints.ai_family AF_UNSPEC;hints.ai_socktype SOCK_STREAM;if (getaddrinfo(addr,portstr,hints,servinfo) ! 0) return -1;for (p servinfo; p ! NULL; p p-ai_next) {/* Try to create the socket and to connect it.* If we fail in the socket() call, or on connect(), we retry with* the next entry in servinfo. */if ((s socket(p-ai_family,p-ai_socktype,p-ai_protocol)) -1)continue;/* Put in non blocking state if needed. */if (nonblock socketSetNonBlockNoDelay(s) -1) {close(s);break;}/* Try to connect. */if (connect(s,p-ai_addr,p-ai_addrlen) -1) {/* If the socket is non-blocking, it is ok for connect() to* return an EINPROGRESS error here. */if (errno EINPROGRESS nonblock) return s;/* Otherwise its an error. */close(s);break;}/* If we ended an iteration of the for loop without errors, we* have a connected socket. Lets return to the caller. */retval s;break;}freeaddrinfo(servinfo);return retval; /* Will be -1 if no connection succeded. */ }/* If the listening socket signaled there is a new connection ready to* be accepted, we accept(2) it and return -1 on error or the new client* socket on success. */ int acceptClient(int server_socket) {int s;while(1) {struct sockaddr_in sa;socklen_t slen sizeof(sa);s accept(server_socket,(struct sockaddr*)sa,slen);if (s -1) {if (errno EINTR)continue; /* Try again. */elsereturn -1;}break;}return s; }/* We also define an allocator that always crashes on out of memory: you* will discover that in most programs designed to run for a long time, that* are not libraries, trying to recover from out of memory is often futile* and at the same time makes the whole program terrible. */ void *chatMalloc(size_t size) {void *ptr malloc(size);if (ptr NULL) {perror(Out of memory);exit(1);}return ptr; }/* Also aborting realloc(). */ void *chatRealloc(void *ptr, size_t size) {ptr realloc(ptr,size);if (ptr NULL) {perror(Out of memory);exit(1);}return ptr; } 参考资料 超详细的Socket通信原理和实例讲解适合初学者的开源Smallchatnc的基本用法telnet 使用教程新手篇及问题集锦linux下文件读取性能比较fread、read、mmap
http://www.zqtcl.cn/news/570268/

相关文章:

  • 网站建设必备网站自助建设
  • 杭州免费自助建站模板辽宁建设工程信息网为什么打不开
  • sdcms网站源码百度怎么免费做网站
  • 图书馆网站参考咨询建设wordpress安装500
  • 详细描述建设网站wordpress 子页面
  • 做公司网站推广如何快速推广
  • 给期货交易类做网站违法吗青海企业网站制作
  • 成都网站模板购买一站式营销型网站建设服务
  • wordpress建站优势做网站认证对网站有什么好处
  • synology做网站专业企业建站价格
  • php开发大型网站开发免费个人微网站
  • 专门做奢侈品的网站怎么建设课题网站
  • 博客推广那个网站列好深圳社保个人网页登录
  • 网站的背景图怎么做最新章节 第一百四十七章 做视频网站
  • 济南网站建设百家号阿里云怎么wordpress
  • 网站分享对联广告北京建设执业网站
  • 一级做爰片免费网站域名流量查询
  • 做网站网站需要注意什么网站建设swot市场分析
  • 大学生兼职网站的融资方案云凡济南网站建设开发
  • 做动态效果的插件网站抚顺清原网站建设招聘
  • 商务网站开发需求分析厦门35网站建设公司
  • wordpress classseo推广服务
  • 石景山网站建设公司网站后台密码如何破解
  • 哪个大学的网站做的最好看南宁网站设计制作公司
  • 北京 集团公司网站建设免费网站建设模版云盘
  • 阿里云建设网站要什么广州网站建设方案案例
  • 德阳吧网站建设线上编程培训机构哪家好
  • 天津电商网站开发备案查询站长之家
  • 网至普的营销型网站布局青岛做网站
  • 网站开发的安全问题wordpress文章列表显示缩略图