socket 
在TCP/IP协议中,“IP地址+TCP/UDP端口号”表示唯一网络通信中的一个进程,IP地址+端口号称为socket。 
注意: 
字节序有大端和小端,在两台使用不同字节序的主机上通信,为了让两台主机间能正确的通信,发送端总是把字节序转成大端字节序数据后在发送,接收方知道接受的一定是大端字节序,然后根据自己的字节序进行转化就不会出错。

浑源网站建设公司创新互联,浑源网站设计制作,有大型网站制作公司丰富经验。已为浑源1000+提供企业网站建设服务。企业网站搭建\
成都外贸网站建设要多少钱,请找那个售后服务好的
浑源做网站的公司定做!调用函数 
int socket(int domain, int type, int protocol)
第一个参数是告诉系统使用哪个底层协议族。对于TCP/IP协议族该参数应该设置为AF_INET/PF_INET用于IPV4,两个值相同可以混用。 第二个参数 SOCK_STREAM表示传输层使用TCP,SOCK_DGRAM表式UDP。 第三个参数通常都设为0,使用默认协议。 
int bind(int sockfd,  struct sockaddr* my_addr, socklen_t len) 
struct sockaddr_in 
{ 
sa_family_t sin_family; //地址族; AF_INET 
u_int16_t  sin_port; //端口号 
struct in_addr sin_addr;   //IPV4地址结构体 
} 
struct in_addr 
{ 
u_int32_t s_addr;   //IPV4地址 
} 
bind是将my_addr所指的socket分配到未命名的sockfd文件描述符。 
int listen(int sockfd, int backlog) 
socket被命名之后不能马上连接,需要listen创建一个监听队列,sockfd是指被监听的socket,backlog是指处于连接状态和socket的上限。
int accept(int sockfd, struct sockaddr*addr, socklen_t *len) 
从listen监听队列中接受一个连接。sockfd是执行过linten接受监听的socket。
单进程的server 
/*************************************************************************     > File Name: tcp_server.c     > Author: weierxiao     > Mail: 1091868910@qq.com      > Created Time: Sat 08 Jul 2017 05:15:29 PM CST  ************************************************************************/  #include #include #include #include #include #include #include #define _PORT_ 9999 #define _BACKLOG_ 10 int main() {     int sock = socket(AF_INET, SOCK_STREAM,0);     if (sock < 0)     {         printf("socket error, errno is %d, errstring is %sn", errno, strerror(errno));     }     struct sockaddr_in server_sock;     struct sockaddr_in client_sock;     bzero(&server_sock, sizeof(server_sock));      server_sock.sin_family = AF_INET;     server_sock.sin_addr.s_addr = htonl(INADDR_ANY);     server_sock.sin_port = htons(_PORT_);      if (bind(sock, (struct sockaddr*)&server_sock, sizeof(struct sockaddr_in))< 0)     {         printf("bind error, errno is %d, errstring is %sn", errno, strerror(errno));         close(sock);         return 1;     }      if (listen(sock, _BACKLOG_)< 0)     {         printf("listen error, errno is %d, errstring is %sn", errno, strerror(errno));         close(sock);         return 2;     }      printf("bind and listen success, wait accept!n");      while (1)     {         socklen_t len = 0;         int client_socket = accept(sock, (struct sockaddr*)&client_sock,&len);         if (client_socket < 0)         {             printf("accept  error, errno is %d, errstring is %sn", errno, strerror(errno));             close(sock);             return 3;         }          char buf_ip[INET_ADDRSTRLEN];         memset(buf_ip, 0, sizeof(buf_ip));         inet_ntop(AF_INET, &client_sock.sin_addr, buf_ip, sizeof(buf_ip));          printf("get connection :ip is  %s, port is %dn ",buf_ip, ntohs(client_sock.sin_port) );          while (1)         {             char buf[1024];             memset(buf, 0, sizeof(buf));              read(client_socket, buf, sizeof(buf));             printf("client# : %sn", buf);             printf("server# :");             memset(buf, 0, sizeof(buf));             fgets(buf, sizeof(buf), stdin);             buf[strlen(buf) - 1 ]= \'�\';             write(client_socket, buf, strlen(buf)+1);             printf("please wait ...n");          }     }      close(sock);     return 0;      }    client客户端
#include #include #include #include #include #include #include #include  #define SERVER_PORT 9999 #define SERVER_IP "192.168.2.103"  int main(int argc, char *argv[]) {      if (argc != 2)     {         printf("Usage : client IPn");         return 1;     }      char *ip = argv[1];     char buf[1024];     memset(buf,0,sizeof(buf));      struct sockaddr_in server_sock;     int sock = socket(AF_INET, SOCK_STREAM, 0);     if (sock < 0)     {         printf("socket error, errno is %d, errstring is %sn", errno, strerror(errno));     }      bzero(&server_sock, sizeof(server_sock));     server_sock.sin_family = AF_INET;     inet_pton(AF_INET, SERVER_IP, &server_sock.sin_addr);     server_sock.sin_port = htons(SERVER_PORT);      int ret = connect(sock, (struct sockaddr*)& server_sock, sizeof(server_sock));      if (ret < 0)     {         printf("connect error, errno is %d, errstring is %sn", errno, strerror(errno));         return 1;     }      printf("connect sucess!n");     while(1)     {         printf("client# :");         fgets(buf, sizeof(buf), stdin);         buf[strlen(buf)-1] = \'�\';         write(sock, buf, sizeof(buf));         if (strncasecmp(buf,"quit", 4) == 0)         {             printf("quit !n");             break;         }         printf("please waitn");         read(sock, buf, sizeof(buf));         printf("server #:%sn", buf);      }     close(sock);     return 0; }
我主机的ip地址是192.168.2.103. 
运行server 
用命令netstat _nltp 可以查看当前主机的tcp服务 
我绑定的是9999端口,ip地址还没确定,运行客户端进行通信 
多进程服务器 
将通信部分让子进程去处理,其他过程让父进程来处理。但是问题来了,只要服务器一直运行,我们的父进程就不会结束,而子进程随时可能结束,这样一来子进程就变成了僵尸进程,那么这个问题怎么处理呢?其实处理这个问题非常巧妙,我们让子进程再fork一次,得到一个孙子进程,然后结束子进程,这样孙子进程就成了孤儿进程,它会被1号进程回收,在这个过程中并没有产生僵尸进程,这个问题就解决了。
#include #include #include #include #include #include #include #include  #define _PORT_ 9999 #define _BACKLOG_ 10 int main() {     int sock = socket(AF_INET, SOCK_STREAM,0);     if (sock < 0)     {         printf("socket error, errno is %d, errstring is %sn", errno, strerror(errno));     }     struct sockaddr_in server_sock;     struct sockaddr_in client_sock;     bzero(&server_sock, sizeof(server_sock));      server_sock.sin_family = AF_INET;     server_sock.sin_addr.s_addr = htonl(INADDR_ANY);     server_sock.sin_port = htons(_PORT_);      if (bind(sock, (struct sockaddr*)&server_sock, sizeof(struct sockaddr_in))< 0)     {         printf("bind error, errno is %d, errstring is %sn", errno, strerror(errno));         close(sock);         return 1;     }      if (listen(sock, _BACKLOG_)< 0)     {         printf("listen error, errno is %d, errstring is %sn", errno, strerror(errno));         close(sock);         return 2;     }      printf("bind and listen success, wait accept!n");      while (1)     {         socklen_t len = 0;         int client_socket = accept(sock, (struct sockaddr*)&client_sock,&len);         if (client_socket < 0)         {             printf("accept  error, errno is %d, errstring is %sn", errno, strerror(errno));             close(sock);             return 3;         }          char buf_ip[INET_ADDRSTRLEN];         memset(buf_ip, 0, sizeof(buf_ip));         inet_ntop(AF_INET, &client_sock.sin_addr, buf_ip, sizeof(buf_ip));          printf("get connection :ip is  %s, port is %dn ",buf_ip, ntohs(client_sock.sin_port) );          pid_t id = fork();         if (id<0)         {             perror("fork");         }         else if(id == 0)         {             close(sock);             pid_t idd = fork();             if (idd < 0)             {                 perror("second fork");                 exit(5);             }             else if (idd == 0)             {                     while (1)                     {                         char buf[1024];                         memset(buf, 0, sizeof(buf));                          read(client_socket, buf, sizeof(buf));                         printf("client# : %sn", buf);                         printf("server# :");                         memset(buf, 0, sizeof(buf));                         fgets(buf, sizeof(buf), stdin);                         buf[strlen(buf) - 1 ]= \'�\';                         write(client_socket, buf, strlen(buf)+1);                         printf("please wait ...n");                      }             }             else              {                 exit(6);             }         }         else         {             close(client_socket);             waitpid(id, NULL,0);         }      }     close(sock);     return 0;      }     多线程服务器
多线程服务器就是将通信部分让一个线程去处理,为了避免线程退出时整个进程退出,我们将线程分离出去。
#include #include #include #include #include #include #include #define _PORT_ 9999 #define _BACKLOG_ 10  void request(void* arg) {     int new_fd = (int )arg;     char buf_ip[INET_ADDRSTRLEN];         memset(buf_ip, 0, sizeof(buf_ip));         inet_ntop(AF_INET, &client_sock.sin_addr, buf_ip, sizeof(buf_ip));          printf("get connection :ip is  %s, port is %dn ",buf_ip, ntohs(client_sock.sin_port) );          while (1)         {             char buf[1024];             memset(buf, 0, sizeof(buf));              read(client_socket, buf, sizeof(buf));             printf("client# : %sn", buf);             printf("server# :");             memset(buf, 0, sizeof(buf));             fgets(buf, sizeof(buf), stdin);             buf[strlen(buf) - 1 ]= \'�\';             write(client_socket, buf, strlen(buf)+1);             printf("please wait ...n");                     }     }  } int main() {     int sock = socket(AF_INET, SOCK_STREAM,0);     if (sock < 0)     {         printf("socket error, errno is %d, errstring is %sn", errno, strerror(errno));     }     struct sockaddr_in server_sock;     struct sockaddr_in client_sock;     bzero(&server_sock, sizeof(server_sock));      server_sock.sin_family = AF_INET;     server_sock.sin_addr.s_addr = htonl(INADDR_ANY);     server_sock.sin_port = htons(_PORT_);      if (bind(sock, (struct sockaddr*)&server_sock, sizeof(struct sockaddr_in))< 0)     {         printf("bind error, errno is %d, errstring is %sn", errno, strerror(errno));         close(sock);         return 1;     }      if (listen(sock, _BACKLOG_)< 0)     {         printf("listen error, errno is %d, errstring is %sn", errno, strerror(errno));         close(sock);         return 2;     }      printf("bind and listen success, wait accept!n");     pthread_t id;     pthread_create(&id, NULL, request, (void*)new_fd );     pthread_detach(id);      close(sock);     return 0;      }    bind失败的原因
当两个 socket 的 address 和 port 相冲突,而你又想重用地址和端口,则旧的 socket 和新的 socket 都要已经被设置了 SO_REUSEADDR 特性,只 有两者之一有这个特性还是有问题的。  
SO_REUSEADDR 可以用在以下四种情况下。  
( 摘自《 Unix 网络编程》卷一,即 UNPv1)  
1 、当有一个有相同本地地址和端口的 socket1 处于 TIME_WAIT 状态时,而你启  
动的程序的 socket2 要占用该地址和端口,你的程序就要用到该选项。  
2 、 SO_REUSEADDR 允许同一 port 上启动同一服务器的多个实例 ( 多个进程 ) 。但  
每个实例绑定的 IP 地址是不能相同的。在有多块网卡或用 IP Alias 技术的机器可  
以测试这种情况。  
3 、 SO_REUSEADDR 允许单个进程绑定相同的端口到多个 socket 上,但每个 soc 
ket 绑定的 ip 地址不同。这和 2 很相似,区别请看 UNPv1 。  
4 、 SO_REUSEADDR 允许完全相同的地址和端口的重复绑定。但这只用于 UDP 的  
多播,不用于 TCP 。
                                                分享名称:TCPserver的实现,和多线程,多进程服务器