最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

Linuxsocket编程

IT圈 admin 1浏览 0评论

Linux socket编程

1.TCP/UDP对比

  1. TCP面向连接(如打电话要先拨号建立连接) ;UDP是无连接的,即发送数据之前不需要建立连接
  2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
  3. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP 是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
  4. 每一条TCP连接只能是点到点的;UDP支持一 对一,一对多,多对一和多对多的交互通信
  5. TCP首部开销20字节;UDP的首部开销小,只有8个字节
  6. TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

2端口号的作用

  1. 一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等

  2. 这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对 多的关系。

  3. 实际上是通过"IP地址+端口号"来区分不同的服务的。
    端口提供了一种访问通道,

  4. 服务器一般都是通过知名 端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务 器的TCP端口号都是21,每个Telnet服 务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69

3. 什么是socket?

网络中的进程是通过socket来通信的,那什么是socket呢?socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。我的理解就是Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭),这些函数我们在后面进行介绍。

一 连接协议socket()函数

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


当protocol为0时,会自动选择type类型对应的默认协议。
当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数。

二 bind()函数

bind()函数把一个地址族中的特定地址赋给socket。

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

  1. sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。
  2. addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4对应的是:`
struct sockaddr
{unsigned short sa_family; /*地址族*/char sa_data[14]; /*14字节的协议地址,包含该socket的IP地址和端口号。*/
};
struct sockaddr_in
{short int sa_family; /*地址族*/unsigned short int sin_port; /*端口号*/struct in_addr sin_addr; /*IP地址*/unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/
};
struct in_addr
{
unsigned long int  s_addr; /* 32位IPv4地址,网络字节序 */
};
头文件<netinet/in.h>
sa_family:AF_INET  IPv4协议   AF_INET6  IPv6协议
国内一般使用的都是IPv4
IPv4的函数原型:#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>int inet_aton(const char *straddr, struct in_addr *addrptr);char *inet_ntoa(struct in_addr inaddr);in_addr_t inet_addr(const char *straddr);函数inet_aton():将点分十进制数的IP地址转换成为网络字节序的32位二进制数值。返回值:成功,则返回1,不成功返回0参数straddr:存放输入的点分十进制数IP地址字符串。
参数addrptr:传出参数,保存网络字节序的32位二进制数值。
函数inet_ntoa():将网络字节序的32位二进制数值转换为点分十进制的IP地址。
函数inet_addr():功能与inet_aton相同,但是结果传递的方式不同。inet_addr()若成功则返回32位二进制的网络字节序地址。

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 */
};

ipv6对应的是:

struct sockaddr_in6 { sa_family_t     sin6_family;   /* AF_INET6 */ in_port_t       sin6_port;     /* port number */ uint32_t        sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr;     /* IPv6 address */ uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};struct in6_addr { unsigned char   s6_addr[16];   /* IPv6 address */ 
};

Unix域对应的是:

#define UNIX_PATH_MAX    108struct sockaddr_un { sa_family_t sun_family;               /* AF_UNIX */ char        sun_path[UNIX_PATH_MAX];  /* pathname */ 
};
  1. addrlen:对应的是地址的长度。

    通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。

三 listen()、connect()函数

  1. int listen(int sockfd, int backlog);
  2. int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。

四 accept()函数

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

accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。

如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。

五 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);

六 close()函数

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

网络字节序与主机字节序

主机字节序就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。引用标准的Big-Endian和Little-Endian的定义如下:

a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

字节序:即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
1. Little endian:将低序字节存储在起始地址
2. Big endian:将高序字节存储在起始地址
网络中使用大大端字节序(Big endian)
四个函数:htons(),ntohs(),htonl()和ntohl().
这四个地址分别实现网络字节序和主机字节序的转化,
这里的h代表host,n代表network,s代表short,l代表long。
通常16位的IP端口号用s代表,而IP地址用l来代表

网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。

所以:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。由于这个问题曾引发过血案!公司项目代码中由于存在这个问题,导致了很多莫名其妙的问题,所以请谨记对主机字节序不要做任何假定,务必将其转化为网络字节序再赋给socket。

服务器代码

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>int main(){int s_fd;int c_fd;int mark = 0;int n_read;char readBuf[128] = {0};char str[128] = {0};struct sockaddr_in s_addr;struct sockaddr_in c_addr;memset(&s_addr,0,sizeof(struct sockaddr_in));memset(&c_addr,0,sizeof(struct sockaddr_in));s_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd == -1){perror("socket");exit(-1);}s_addr.sin_family = AF_INET;s_addr.sin_port  = htons(8989);inet_aton("127.0.0.1",&s_addr.sin_addr);bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));listen(s_fd,10);int len = sizeof(struct sockaddr_in);while(1){c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&len);if(c_fd == -1 ){perror("accept");exit(-1);}mark++;printf("connect sucess : %s\n",inet_ntoa(c_addr.sin_addr));if(fork() == 0){if(fork()==0){while(1){sprintf(str,"welcome NO.%d  client\n",mark);write(c_fd,str, strlen(str));sleep(4);}}while(1){memset(readBuf,0,sizeof(readBuf));n_read = read(c_fd,&readBuf,128);if(n_read ==-1){perror("read:");exit(-1);}elseprintf("receve msg from client : %s\n ", readBuf);}}}return 0;
}

因为多个客户端同时接入时会有资源竞争,所以在服务端在向发送数据时,不确定那个客户端能收到,并且只有一个客户端能收到,所以对服务端进行简易改进(Mark++来代表几=记录第几个客户端连接,每连接一个Mark会加1),实现多方数据通信。首先不断向客户端发送数据,确保通讯,然后不同客户端可任意向客服端发送数据,服务端可监听所有数据。

此次改进只为让服务端成为一个中转站,小改一下,太复杂的目前水平无法实现

客户端代码

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>int main(){int c_fd;int n_read;char msg[128]={0};char readBuf[128] = {0};struct sockaddr_in c_addr;memset(&c_addr,0,sizeof(struct sockaddr_in));c_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd == -1){perror("socket");exit(-1);}c_addr.sin_family = AF_INET;c_addr.sin_port  = htons(8089);inet_aton("127.20.0.1",&c_addr.sin_addr);if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){                          perror("connect : ");exit(-1);}while(1){if(fork()==0){while(1){memset(msg, 0 , sizeof(msg));printf("plesase input msg : \n");gets(msg);write(c_fd, msg ,strlen(msg));}while(1){memset(readBuf, 0 , sizeof(readBuf));n_read = read(c_fd,readBuf,128);if(n_read ==-1){perror("read:");exit(-1);}elseprintf(" message from sever %s\n ", readBuf);}}return 0;
}

Linux socket编程

1.TCP/UDP对比

  1. TCP面向连接(如打电话要先拨号建立连接) ;UDP是无连接的,即发送数据之前不需要建立连接
  2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
  3. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP 是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
  4. 每一条TCP连接只能是点到点的;UDP支持一 对一,一对多,多对一和多对多的交互通信
  5. TCP首部开销20字节;UDP的首部开销小,只有8个字节
  6. TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

2端口号的作用

  1. 一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等

  2. 这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对 多的关系。

  3. 实际上是通过"IP地址+端口号"来区分不同的服务的。
    端口提供了一种访问通道,

  4. 服务器一般都是通过知名 端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务 器的TCP端口号都是21,每个Telnet服 务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69

3. 什么是socket?

网络中的进程是通过socket来通信的,那什么是socket呢?socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。我的理解就是Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭),这些函数我们在后面进行介绍。

一 连接协议socket()函数

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


当protocol为0时,会自动选择type类型对应的默认协议。
当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数。

二 bind()函数

bind()函数把一个地址族中的特定地址赋给socket。

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

  1. sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。
  2. addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4对应的是:`
struct sockaddr
{unsigned short sa_family; /*地址族*/char sa_data[14]; /*14字节的协议地址,包含该socket的IP地址和端口号。*/
};
struct sockaddr_in
{short int sa_family; /*地址族*/unsigned short int sin_port; /*端口号*/struct in_addr sin_addr; /*IP地址*/unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/
};
struct in_addr
{
unsigned long int  s_addr; /* 32位IPv4地址,网络字节序 */
};
头文件<netinet/in.h>
sa_family:AF_INET  IPv4协议   AF_INET6  IPv6协议
国内一般使用的都是IPv4
IPv4的函数原型:#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>int inet_aton(const char *straddr, struct in_addr *addrptr);char *inet_ntoa(struct in_addr inaddr);in_addr_t inet_addr(const char *straddr);函数inet_aton():将点分十进制数的IP地址转换成为网络字节序的32位二进制数值。返回值:成功,则返回1,不成功返回0参数straddr:存放输入的点分十进制数IP地址字符串。
参数addrptr:传出参数,保存网络字节序的32位二进制数值。
函数inet_ntoa():将网络字节序的32位二进制数值转换为点分十进制的IP地址。
函数inet_addr():功能与inet_aton相同,但是结果传递的方式不同。inet_addr()若成功则返回32位二进制的网络字节序地址。

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 */
};

ipv6对应的是:

struct sockaddr_in6 { sa_family_t     sin6_family;   /* AF_INET6 */ in_port_t       sin6_port;     /* port number */ uint32_t        sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr;     /* IPv6 address */ uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};struct in6_addr { unsigned char   s6_addr[16];   /* IPv6 address */ 
};

Unix域对应的是:

#define UNIX_PATH_MAX    108struct sockaddr_un { sa_family_t sun_family;               /* AF_UNIX */ char        sun_path[UNIX_PATH_MAX];  /* pathname */ 
};
  1. addrlen:对应的是地址的长度。

    通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。

三 listen()、connect()函数

  1. int listen(int sockfd, int backlog);
  2. int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。

四 accept()函数

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

accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。

如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。

五 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);

六 close()函数

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

网络字节序与主机字节序

主机字节序就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。引用标准的Big-Endian和Little-Endian的定义如下:

a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

字节序:即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
1. Little endian:将低序字节存储在起始地址
2. Big endian:将高序字节存储在起始地址
网络中使用大大端字节序(Big endian)
四个函数:htons(),ntohs(),htonl()和ntohl().
这四个地址分别实现网络字节序和主机字节序的转化,
这里的h代表host,n代表network,s代表short,l代表long。
通常16位的IP端口号用s代表,而IP地址用l来代表

网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。

所以:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。由于这个问题曾引发过血案!公司项目代码中由于存在这个问题,导致了很多莫名其妙的问题,所以请谨记对主机字节序不要做任何假定,务必将其转化为网络字节序再赋给socket。

服务器代码

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>int main(){int s_fd;int c_fd;int mark = 0;int n_read;char readBuf[128] = {0};char str[128] = {0};struct sockaddr_in s_addr;struct sockaddr_in c_addr;memset(&s_addr,0,sizeof(struct sockaddr_in));memset(&c_addr,0,sizeof(struct sockaddr_in));s_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd == -1){perror("socket");exit(-1);}s_addr.sin_family = AF_INET;s_addr.sin_port  = htons(8989);inet_aton("127.0.0.1",&s_addr.sin_addr);bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));listen(s_fd,10);int len = sizeof(struct sockaddr_in);while(1){c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&len);if(c_fd == -1 ){perror("accept");exit(-1);}mark++;printf("connect sucess : %s\n",inet_ntoa(c_addr.sin_addr));if(fork() == 0){if(fork()==0){while(1){sprintf(str,"welcome NO.%d  client\n",mark);write(c_fd,str, strlen(str));sleep(4);}}while(1){memset(readBuf,0,sizeof(readBuf));n_read = read(c_fd,&readBuf,128);if(n_read ==-1){perror("read:");exit(-1);}elseprintf("receve msg from client : %s\n ", readBuf);}}}return 0;
}

因为多个客户端同时接入时会有资源竞争,所以在服务端在向发送数据时,不确定那个客户端能收到,并且只有一个客户端能收到,所以对服务端进行简易改进(Mark++来代表几=记录第几个客户端连接,每连接一个Mark会加1),实现多方数据通信。首先不断向客户端发送数据,确保通讯,然后不同客户端可任意向客服端发送数据,服务端可监听所有数据。

此次改进只为让服务端成为一个中转站,小改一下,太复杂的目前水平无法实现

客户端代码

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>int main(){int c_fd;int n_read;char msg[128]={0};char readBuf[128] = {0};struct sockaddr_in c_addr;memset(&c_addr,0,sizeof(struct sockaddr_in));c_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd == -1){perror("socket");exit(-1);}c_addr.sin_family = AF_INET;c_addr.sin_port  = htons(8089);inet_aton("127.20.0.1",&c_addr.sin_addr);if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){                          perror("connect : ");exit(-1);}while(1){if(fork()==0){while(1){memset(msg, 0 , sizeof(msg));printf("plesase input msg : \n");gets(msg);write(c_fd, msg ,strlen(msg));}while(1){memset(readBuf, 0 , sizeof(readBuf));n_read = read(c_fd,readBuf,128);if(n_read ==-1){perror("read:");exit(-1);}elseprintf(" message from sever %s\n ", readBuf);}}return 0;
}

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论