Basic socket programming in the C language
- 2020-05-05 11:38:25
- OfStack
What is socket
You often hear people talk about "socket", and you may not know exactly what it means. Now let me tell you: it's a way to communicate with other programs using the standard Unix file descriptor (file descriptor). What? You may have heard some Unix pros say, "gee, everything in Unix is a file!" The guy might be talking about the fact that the Unix program reads or writes a file descriptor while executing any form of I/O. A file descriptor is simply an integer associated with an open file. But (note later), the file could be a network connection, FIFO, pipe, terminal, file on disk, or something else. Everything in Unix is a file! So, when you want to communicate with another program on Internet, you're going to use the file descriptor. You have to understand that. Now you might be thinking, "so where do I get the file descriptors for network communications?" This is a question I will answer anyway: you use the system call socket(), which returns the socket descriptor (socket descriptor), and then you use it to make send() and recv() calls. "But..." If it's a file descriptor, why not call read() and write() for socket communication? The simple answer is: "you can use it!" . The detailed answer is: "you can, but using send() and recv() gives you better control over the data transfer." There is a situation where there are many kinds of sockets in our world. There are DARPA Internet addresses (Internet sockets), local node pathnames (Unix sockets), and CCITT X.25 addresses (you can ignore X.25 sockets entirely). Maybe there are others on your Unix machine. We will only cover the first type here: Internet sockets.
There are two types of Internet sockets:
What do you mean? Are there two types of Internet sockets? B: yes. No, I'm lying. There's more, but I don't want to scare you. We're only going to talk about two. In addition to these, the "Raw Sockets" I'm going to introduce is also very powerful and worth looking up.
So what are these two types? One is "Stream Sockets" (stream format), and the other is "Datagram Sockets" (packet format). We'll also use "SOCK_STREAM" and "SOCK_DGRAM" when we talk about them later. Datagram sockets are sometimes called "connectionless sockets" (connect() if you really want to connect). A streaming socket is a reliable two-way communication data stream. If you output "1,2" to the socket in order, they will go to the other side in order "1,2". They are error-free and have their own error control, not discussed here.
What is using streaming sockets? You've probably heard of telnet, haven't you? It just USES a streaming socket. You need the characters you type to arrive in order, don't you? Also, the HTTP protocol used by the WWW browser USES them to download pages. In fact, when you go to an WWW site via port 80 telnet and type "GET pagename", you can also get HTML content. Why can streaming socket achieve high quality data transmission? This is because it USES the transport control protocol (The Transmission Control Protocol), also known as TCP (see RFC-793 for details). TCP controls your data to arrive in order and there are no errors with
By mistake. You might hear "TCP" because you've heard "TCP/IP". IP here means "Internet agreement" (please refer to RFC-791). IP just handles Internet routing.
what about datagram sockets? Why is it called connectionless? Why is it unreliable? There are some facts: if you send a datagram, it may arrive, it may be in reverse order. If it arrives, it is error free inside the package. Datagrams also use IP for routing, but it does not use TCP. It USES the user datagram protocol (User Datagram Protocol), also known as UDP (see RFC-768).
why are they connectionless? Mainly because it does not maintain a connection as a streaming socket does. You just create a package, construct an IP header with target information, and send it. No connection required. They are commonly used to transfer package-packet information. Simple applications include: tftp, bootp, and so on.
You may be thinking, "how will these programs work if data is lost?" My friend, each program has its own protocol on UDP. For example, every time a packet is received under the tftp protocol, the recipient must send back a packet saying "I got it!" A "command correct reply" package is also called "ACK". If the sender does not receive a reply within a certain period of time (for example, 5 seconds), it will resend until it gets ACK. This ACK procedure is important when implementing the SOCK_DGRAM application.
simple send and receive implementation
Server-side receive code:
#include <Winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
#include <stdio.h>
#include <memory.h>
void main()
{
WSAData wsd;
WSAStartup(MAKEWORD(2,0),&wsd);
SOCKET s =NULL;
s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in ch;
memset(&ch,0,sizeof(ch));
ch.sin_family=AF_INET;
ch.sin_addr.s_addr=INADDR_ANY;
ch.sin_port=htons(1041);
int b=bind(s,(struct sockaddr *) &ch,sizeof(ch));
#define QUEUE_SIZE 5
int l=listen(s,QUEUE_SIZE);
printf(" Listening on the machine 1041 Port! \n");
SOCKET sc=accept(s,0,0);
printf(" The client is already connected to the native 1041 Port! \n");
#define BUF_SIZE 4096
int receByt=0;
while(1)
{
char buf[BUF_SIZE];
receByt=recv(sc,buf,BUF_SIZE,0);
buf[receByt]='\0';
if(receByt>0)
{
printf(" The message received is: %s\n",buf);
}
else
{
printf(" End of receiving message! ");
break;
}
}
int ic=closesocket(sc);
int is=closesocket(s);
}
Code sent by client:
#include <Winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
#include <stdio.h>
#include <memory.h>
#include <string.h>
void main()
{
WSAData wsd;
WSAStartup(MAKEWORD(2,0),&wsd);
SOCKET s =NULL;
s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in ch;
memset(&ch,0,sizeof(ch));
ch.sin_family=AF_INET;
ch.sin_addr.s_addr=inet_addr("127.0.0.1");
ch.sin_port=htons(1041);
int c=connect(s,(struct sockaddr *) &ch,sizeof(ch));
printf(" Already connected to the server 1041 Port! Now you can send a message to the server! \n");
#define BUF_SIZE 4096
char info[1024],buf[BUF_SIZE];
while(1)
{
gets(info);
if(info[0]=='\0')
break;
strcpy(buf,info);
int nsend=send(s,buf,strlen(buf),0);
}
int ic=closesocket(s);
}
Program code has been optimized, and integration of multi-threading, receive and send into the same file, using parameter mode to call the send and receive module. When creating SOCKET, the s handle (or object) determines whether the return value is INVALID_SOCKET, and whether the return value of bind operation of socket is SOCKET_ERROR. Other socket operations should also determine SOCKET_ERROR to ensure the stability of the program.
#include <Winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <pthread.h>
void Receive();
void Send();
void creatThread();
SOCKET s =NULL;
pthread_t t[1000];
int threadCount=0;
void main(int argc,char* argv[])
{
printf(" Program producer student no. : 713901040041\n");
printf(" Program description: server and client for the same program, please use different parameters to run .\n");
printf(" Please use the receiving program r Parameters; Please use the sending program s Parameters. \n");
//printf("len : %d\n", argc);
//printf("count %d\n",argc);
//printf("value: %s\n",argv[1]);
//printf("%d",argv[1][0]=='r');
if(argc<=1)
{
printf("please input program arguments ...\n");
exit(0);
}
if(argc>1 && argv[1][0]=='r')
{
printf("run receive ...\n");
Receive();
}
if(argc>1 && argv[1][0]=='s')
{
printf("run send ...\n");
Send();
}
}
void* receiveWork(void * args)
{
SOCKET sc=accept(s,0,0);
if(sc==INVALID_SOCKET)
{
printf("sc Error");
}
creatThread();
printf("---------- The client is already connected to the native %d Thread connection! \n",threadCount-2);
#define BUF_SIZE 4096
int receByt=0;
while(1)
{
char buf[BUF_SIZE];
receByt=recv(sc,buf,BUF_SIZE,0);
buf[receByt]='\0';
if(receByt>0)
{
printf(" The message received by the thread is: %s\n",buf);
}
else
{
printf(" The client has exited, ");
break;
}
}
int ic=closesocket(sc);
printf(" Server ends connection! \n");
return NULL;
}
void creatThread()
{
pthread_create(&t[threadCount++],NULL,receiveWork,NULL);
}
void Receive()
{
WSAData wsd;
WSAStartup(MAKEWORD(2,0),&wsd);
s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s==INVALID_SOCKET)
{
printf("socket created Error");
}
struct sockaddr_in ch;
memset(&ch,0,sizeof(ch));
ch.sin_family=AF_INET;
ch.sin_addr.s_addr=INADDR_ANY;
ch.sin_port=htons(1041);
int b=bind(s,(struct sockaddr *) &ch,sizeof(ch));
if(b==SOCKET_ERROR)
{
printf("bind Failure, error code is: %d\n",WSAGetLastError());
exit(0);
}
#define QUEUE_SIZE 5
int l=listen(s,QUEUE_SIZE);
printf(" Listening on the machine 1041 Port! \n");
creatThread();
for(int i=0;i<1000;i++)
{
pthread_join(t[i],NULL);
}
int is=closesocket(s);
}
void Send()
{
WSAData wsd;
WSAStartup(MAKEWORD(2,0),&wsd);
SOCKET s =NULL;
s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s==INVALID_SOCKET)
{
printf("socket created Error");
}
struct sockaddr_in ch;
memset(&ch,0,sizeof(ch));
ch.sin_family=AF_INET;
ch.sin_addr.s_addr=inet_addr("127.0.0.1");
ch.sin_port=htons(1041);
int c=connect(s,(struct sockaddr *) &ch,sizeof(ch));
printf(" Already connected to the server 1041 Port! Now you can send a message to the server! \n");
#define BUF_SIZE 4096
char info[1024],buf[BUF_SIZE];
while(1)
{
gets(info);
if(info[0]=='\0')
break;
strcpy(buf,info);
int nsend=send(s,buf,strlen(buf),0);
}
int ic=closesocket(s);
}